diff --git a/UnicodeCharacterInspector/App.xaml b/UnicodeCharacterInspector/App.xaml
index 6063d01..5bbd14d 100644
--- a/UnicodeCharacterInspector/App.xaml
+++ b/UnicodeCharacterInspector/App.xaml
@@ -6,5 +6,6 @@
+
diff --git a/UnicodeCharacterInspector/CharacterInfoViewModel.cs b/UnicodeCharacterInspector/CharacterInfoViewModel.cs
index 9947d2e..7b9e67a 100644
--- a/UnicodeCharacterInspector/CharacterInfoViewModel.cs
+++ b/UnicodeCharacterInspector/CharacterInfoViewModel.cs
@@ -49,19 +49,30 @@ namespace UnicodeCharacterInspector
}
NotifyPropertyChanged();
- NotifyPropertyChanged("CodePoint");
- NotifyPropertyChanged("Name");
- NotifyPropertyChanged("OldName");
- NotifyPropertyChanged("Category");
- NotifyPropertyChanged("Block");
- NotifyPropertyChanged("CanonicalCombiningClass");
- NotifyPropertyChanged("BidirectionalClass");
- NotifyPropertyChanged("DecompositionType");
- NotifyPropertyChanged("DecompositionMapping");
- NotifyPropertyChanged("NumericType");
- NotifyPropertyChanged("NumericValue");
- NotifyPropertyChanged("ContributoryProperties");
- NotifyPropertyChanged("CoreProperties");
+ NotifyPropertyChanged(nameof(CodePoint));
+ NotifyPropertyChanged(nameof(Name));
+ NotifyPropertyChanged(nameof(OldName));
+ NotifyPropertyChanged(nameof(Definition));
+ NotifyPropertyChanged(nameof(Category));
+ NotifyPropertyChanged(nameof(Block));
+ NotifyPropertyChanged(nameof(CanonicalCombiningClass));
+ NotifyPropertyChanged(nameof(BidirectionalClass));
+ NotifyPropertyChanged(nameof(DecompositionType));
+ NotifyPropertyChanged(nameof(DecompositionMapping));
+ NotifyPropertyChanged(nameof(NumericType));
+ NotifyPropertyChanged(nameof(UnihanNumericType));
+ NotifyPropertyChanged(nameof(NumericValue));
+ NotifyPropertyChanged(nameof(ContributoryProperties));
+ NotifyPropertyChanged(nameof(CoreProperties));
+ NotifyPropertyChanged(nameof(MandarinReading));
+ NotifyPropertyChanged(nameof(CantoneseReading));
+ NotifyPropertyChanged(nameof(JapaneseKunReading));
+ NotifyPropertyChanged(nameof(JapaneseOnReading));
+ NotifyPropertyChanged(nameof(KoreanReading));
+ NotifyPropertyChanged(nameof(HangulReading));
+ NotifyPropertyChanged(nameof(VietnameseReading));
+ NotifyPropertyChanged(nameof(SimplifiedVariant));
+ NotifyPropertyChanged(nameof(TraditionalVariant));
}
}
}
@@ -81,6 +92,11 @@ namespace UnicodeCharacterInspector
get { return character != null ? characterInfo.OldName : null; }
}
+ public string Definition
+ {
+ get { return character != null ? characterInfo.Definition : null; }
+ }
+
public UnicodeCategory? Category
{
get { return character != null ? characterInfo.Category : null as UnicodeCategory?; }
@@ -116,6 +132,11 @@ namespace UnicodeCharacterInspector
get { return character != null ? characterInfo.NumericType : null as UnicodeNumericType?; }
}
+ public UnihanNumericType? UnihanNumericType
+ {
+ get { return character != null ? characterInfo.UnihanNumericType : null as UnihanNumericType?; }
+ }
+
public UnicodeRationalNumber? NumericValue
{
get { return character != null && characterInfo.NumericType != UnicodeNumericType.None ? characterInfo.NumericValue : null as UnicodeRationalNumber?; }
@@ -130,5 +151,50 @@ namespace UnicodeCharacterInspector
{
get { return character != null ? characterInfo.CoreProperties : null as CoreProperties?; }
}
+
+ public string MandarinReading
+ {
+ get { return character != null ? characterInfo.MandarinReading : null; }
+ }
+
+ public string CantoneseReading
+ {
+ get { return character != null ? characterInfo.CantoneseReading : null; }
+ }
+
+ public string JapaneseKunReading
+ {
+ get { return character != null ? characterInfo.JapaneseKunReading : null; }
+ }
+
+ public string JapaneseOnReading
+ {
+ get { return character != null ? characterInfo.JapaneseOnReading : null; }
+ }
+
+ public string KoreanReading
+ {
+ get { return character != null ? characterInfo.KoreanReading : null; }
+ }
+
+ public string HangulReading
+ {
+ get { return character != null ? characterInfo.HangulReading : null; }
+ }
+
+ public string VietnameseReading
+ {
+ get { return character != null ? characterInfo.VietnameseReading : null; }
+ }
+
+ public string SimplifiedVariant
+ {
+ get { return character != null ? characterInfo.SimplifiedVariant : null; }
+ }
+
+ public string TraditionalVariant
+ {
+ get { return character != null ? characterInfo.TraditionalVariant : null; }
+ }
}
}
diff --git a/UnicodeCharacterInspector/MainWindow.xaml b/UnicodeCharacterInspector/MainWindow.xaml
index 7820420..5790bb3 100644
--- a/UnicodeCharacterInspector/MainWindow.xaml
+++ b/UnicodeCharacterInspector/MainWindow.xaml
@@ -75,6 +75,10 @@
+
+
+
+
@@ -83,26 +87,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UnicodeCharacterInspector/UnicodeCharacterInspector.csproj b/UnicodeCharacterInspector/UnicodeCharacterInspector.csproj
index b767a37..c50bb47 100644
--- a/UnicodeCharacterInspector/UnicodeCharacterInspector.csproj
+++ b/UnicodeCharacterInspector/UnicodeCharacterInspector.csproj
@@ -69,6 +69,7 @@
+
MainWindow.xaml
diff --git a/UnicodeCharacterInspector/ZeroToVisibilityConverter.cs b/UnicodeCharacterInspector/ZeroToVisibilityConverter.cs
new file mode 100644
index 0000000..fe46568
--- /dev/null
+++ b/UnicodeCharacterInspector/ZeroToVisibilityConverter.cs
@@ -0,0 +1,24 @@
+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;
+
+namespace UnicodeCharacterInspector
+{
+ internal sealed class ZeroToVisibilityConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value != null && System.Convert.ToInt32(value) != 0 ? Visibility.Visible : Visibility.Collapsed;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/UnicodeInformation.Builder/CharacterDecompositionMapping.cs b/UnicodeInformation.Builder/CharacterDecompositionMapping.cs
index 17ded32..c5709de 100644
--- a/UnicodeInformation.Builder/CharacterDecompositionMapping.cs
+++ b/UnicodeInformation.Builder/CharacterDecompositionMapping.cs
@@ -46,7 +46,7 @@ namespace System.Unicode.Builder
if (c == ' ') ++index;
else
{
- int codePoint = ParseCodePoint(s, ref index);
+ int codePoint = HexCodePoint.Parse(s, ref index);
if (codePoint < 0x10000)
buffer[charIndex++] = (char)codePoint;
@@ -65,30 +65,5 @@ namespace System.Unicode.Builder
return new CharacterDecompositionMapping(tag, new string(buffer, 0, charIndex));
}
-
- private static int ParseCodePoint(string s, ref int index)
- {
- int i = index;
- int accum = 0;
-
- while (i < s.Length)
- {
- char c = s[i];
-
- if (c == ' ') break;
-
- accum <<= 4;
-
- if (c >= '0' && c <= '9') accum |= c - '0';
- else if (c >= 'A' && c <= 'F') accum |= c - 'A' + 0xA;
- else if (c >= 'a' && c <= 'f') accum |= c - 'a' + 0xA;
- else throw new FormatException();
-
- ++i;
- }
-
- index = i;
- return accum;
- }
}
}
diff --git a/UnicodeInformation.Builder/HexCodePoint.cs b/UnicodeInformation.Builder/HexCodePoint.cs
new file mode 100644
index 0000000..9f63d99
--- /dev/null
+++ b/UnicodeInformation.Builder/HexCodePoint.cs
@@ -0,0 +1,44 @@
+namespace System.Unicode.Builder
+{
+ public static class HexCodePoint
+ {
+ public static int ParsePrefixed(string s)
+ {
+ if (!s.StartsWith("U+"))
+ {
+ throw new FormatException("Expected a code point in the form U+nnnn.");
+ }
+ return Parse(s, 2);
+ }
+
+ public static int Parse(string s, int index)
+ {
+ return Parse(s, ref index);
+ }
+
+ public static int Parse(string s, ref int index)
+ {
+ int i = index;
+ int accum = 0;
+
+ while (i < s.Length)
+ {
+ char c = s[i];
+
+ if (c == ' ') break;
+
+ accum <<= 4;
+
+ if (c >= '0' && c <= '9') accum |= c - '0';
+ else if (c >= 'A' && c <= 'F') accum |= c - 'A' + 0xA;
+ else if (c >= 'a' && c <= 'f') accum |= c - 'a' + 0xA;
+ else throw new FormatException();
+
+ ++i;
+ }
+
+ index = i;
+ return accum;
+ }
+ }
+}
diff --git a/UnicodeInformation.Builder/UnicodeDataFileReader.cs b/UnicodeInformation.Builder/UnicodeDataFileReader.cs
index f40567a..7aac2ab 100644
--- a/UnicodeInformation.Builder/UnicodeDataFileReader.cs
+++ b/UnicodeInformation.Builder/UnicodeDataFileReader.cs
@@ -9,80 +9,24 @@ namespace System.Unicode.Builder
{
public class UnicodeDataFileReader : IDisposable
{
- private struct Utf8Buffer
- {
- private readonly UnicodeDataFileReader reader;
- private int length;
-
- public Utf8Buffer(UnicodeDataFileReader reader)
- {
- this.reader = reader;
- this.length = 0;
- }
-
- public int Length { get { return length; } }
-
- private void EnsureExtraCapacity(int count)
- {
- if (count < 0) throw new ArgumentOutOfRangeException("requiredExtraCapacity");
- if (reader.utf8StringBuffer.Length < checked(length + count))
- Array.Resize(ref reader.utf8StringBuffer, Math.Max(length + count, reader.utf8StringBuffer.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");
-
- EnsureExtraCapacity(value.Length);
-
- var buffer = reader.utf8StringBuffer;
-
- for (int i = startIndex; i < count; ++i)
- {
- buffer[length++] = value[i];
- }
- }
-
- public override string ToString()
- {
- return length > 0 ? Encoding.UTF8.GetString(reader.utf8StringBuffer, 0, length) : string.Empty;
- }
-
- public string ToTrimmedString()
- {
- if (length == 0) return string.Empty;
-
- var buffer = reader.utf8StringBuffer;
- int start = 0;
- int end = length;
-
- while (buffer[start] == ' ') if (++start == length) return string.Empty;
- while (buffer[--end] == ' ') ;
-
- return length > 0 ? Encoding.UTF8.GetString(reader.utf8StringBuffer, start, end - start + 1) : string.Empty;
- }
- }
-
private readonly Stream stream;
private readonly byte[] byteBuffer;
- private byte[] utf8StringBuffer;
private int index;
private int length;
+ private readonly char fieldSeparator;
private bool hasField = false;
private readonly bool leaveOpen;
- public UnicodeDataFileReader(Stream stream)
- : this(stream, false)
+ public UnicodeDataFileReader(Stream stream, char fieldSeparator)
+ : this(stream, fieldSeparator, false)
{
}
- public UnicodeDataFileReader(Stream stream, bool leaveOpen)
+ public UnicodeDataFileReader(Stream stream, char fieldSeparator, bool leaveOpen)
{
this.stream = stream;
+ this.fieldSeparator = fieldSeparator;
this.byteBuffer = new byte[8192];
- this.utf8StringBuffer = new byte[100];
this.leaveOpen = leaveOpen;
}
@@ -163,49 +107,51 @@ namespace System.Unicode.Builder
}
}
- var buffer = new Utf8Buffer(this);
- int startOffset;
- int endOffset;
-
- do
+ using (var buffer = Utf8Buffer.Get())
{
- startOffset = index;
- endOffset = -1;
+ int startOffset;
+ int endOffset;
- while (index < length)
+ do
{
- byte b = byteBuffer[index];
+ startOffset = index;
+ endOffset = -1;
- if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
+ while (index < length)
{
- endOffset = index;
- hasField = false;
+ byte b = byteBuffer[index];
+
+ if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
+ {
+ endOffset = index;
+ hasField = false;
+ break;
+ }
+ else if (b == fieldSeparator)
+ {
+ endOffset = index++;
+ break;
+ }
+ else
+ {
+ ++index;
+ }
+ }
+
+ if (endOffset >= 0)
+ {
+ buffer.Append(byteBuffer, startOffset, endOffset - startOffset);
break;
}
- else if(b == ';')
+ else if (index > startOffset)
{
- endOffset = index++;
- break;
+ buffer.Append(byteBuffer, startOffset, index - startOffset);
}
- else
- {
- ++index;
- }
- }
+ } while (RefillBuffer());
- if (endOffset >= 0)
- {
- buffer.Append(byteBuffer, startOffset, endOffset - startOffset);
- break;
- }
- else if (index > startOffset)
- {
- buffer.Append(byteBuffer, startOffset, index - startOffset);
- }
- } while (RefillBuffer());
-
- return trim ? buffer.ToTrimmedString() : buffer.ToString();
- }
+ return trim ? buffer.ToTrimmedString() : buffer.ToString();
+ }
+ }
/// Reads the next data field.
/// This method will return on end of line.
@@ -255,7 +201,7 @@ namespace System.Unicode.Builder
{
++index;
- if (b == ';')
+ if (b == fieldSeparator)
{
return true;
}
diff --git a/UnicodeInformation.Builder/UnicodeDataProcessor.cs b/UnicodeInformation.Builder/UnicodeDataProcessor.cs
index 93a90a9..6deb488 100644
--- a/UnicodeInformation.Builder/UnicodeDataProcessor.cs
+++ b/UnicodeInformation.Builder/UnicodeDataProcessor.cs
@@ -14,6 +14,9 @@ namespace System.Unicode.Builder
public const string PropListFileName = "PropList.txt";
public const string DerivedCorePropertiesFileName = "DerivedCoreProperties.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";
private static string ParseSimpleCaseMapping(string mapping)
{
@@ -35,13 +38,16 @@ namespace System.Unicode.Builder
await ProcessPropListFile(ucdSource, builder).ConfigureAwait(false);
await ProcessDerivedCorePropertiesFile(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);
return builder;
}
private static async Task ProcessUnicodeDataFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
{
- using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(UnicodeDataFileName).ConfigureAwait(false)))
+ using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(UnicodeDataFileName).ConfigureAwait(false), ';'))
{
int rangeStartCodePoint = -1;
@@ -158,7 +164,7 @@ namespace System.Unicode.Builder
private static async Task ProcessPropListFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
{
- using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(PropListFileName).ConfigureAwait(false)))
+ using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(PropListFileName).ConfigureAwait(false), ';'))
{
while (reader.MoveToNextLine())
{
@@ -175,7 +181,7 @@ namespace System.Unicode.Builder
private static async Task ProcessDerivedCorePropertiesFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
{
- using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(DerivedCorePropertiesFileName).ConfigureAwait(false)))
+ using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(DerivedCorePropertiesFileName).ConfigureAwait(false), ';'))
{
while (reader.MoveToNextLine())
{
@@ -192,7 +198,7 @@ namespace System.Unicode.Builder
private static async Task ProcessBlocksFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
{
- using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(BlocksFileName).ConfigureAwait(false)))
+ using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(BlocksFileName).ConfigureAwait(false), ';'))
{
while (reader.MoveToNextLine())
{
@@ -200,5 +206,126 @@ namespace System.Unicode.Builder
}
}
}
+
+ private static async Task ProcessUnihanReadings(IDataSource unihanDataSource, UnicodeInfoBuilder builder)
+ {
+ using (var reader = new UnihanDataFileReader(await unihanDataSource.OpenDataFileAsync(UnihanReadingsFileName).ConfigureAwait(false)))
+ {
+ while (reader.Read())
+ {
+ // This statement is used to skip unhandled properties entirely.
+ switch (reader.PropertyName)
+ {
+ case UnihanProperty.kDefinition:
+ case UnihanProperty.kMandarin:
+ case UnihanProperty.kCantonese:
+ case UnihanProperty.kJapaneseKun:
+ case UnihanProperty.kJapaneseOn:
+ case UnihanProperty.kKorean:
+ case UnihanProperty.kHangul:
+ case UnihanProperty.kVietnamese:
+ break;
+ default:
+ // Ignore unhandled properties for now.
+ continue;
+ }
+
+ // This entry will only be created if there is meaningful data.
+ var entry = builder.GetUnihan(reader.CodePoint);
+
+ switch (reader.PropertyName)
+ {
+ case UnihanProperty.kDefinition:
+ entry.Definition = reader.PropertyValue;
+ break;
+ case UnihanProperty.kMandarin:
+ entry.MandarinReading = reader.PropertyValue;
+ break;
+ case UnihanProperty.kCantonese:
+ entry.CantoneseReading = reader.PropertyValue;
+ break;
+ case UnihanProperty.kJapaneseKun:
+ entry.JapaneseKunReading = reader.PropertyValue;
+ break;
+ case UnihanProperty.kJapaneseOn:
+ entry.JapaneseOnReading = reader.PropertyValue;
+ break;
+ case UnihanProperty.kKorean:
+ entry.KoreanReading = reader.PropertyValue;
+ break;
+ case UnihanProperty.kHangul:
+ entry.HangulReading = reader.PropertyValue;
+ break;
+ case UnihanProperty.kVietnamese:
+ entry.VietnameseReading = reader.PropertyValue;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+ }
+ }
+
+ private static async Task ProcessUnihanVariants(IDataSource unihanDataSource, UnicodeInfoBuilder builder)
+ {
+ using (var reader = new UnihanDataFileReader(await unihanDataSource.OpenDataFileAsync(UnihanVariantsFileName).ConfigureAwait(false)))
+ {
+ while (reader.Read())
+ {
+ // This statement is used to skip unhandled properties entirely.
+ switch (reader.PropertyName)
+ {
+ case UnihanProperty.kSimplifiedVariant:
+ case UnihanProperty.kTraditionalVariant:
+ break;
+ default:
+ // Ignore unhandled properties for now.
+ continue;
+ }
+
+ var entry = builder.GetUnihan(reader.CodePoint);
+
+ switch (reader.PropertyName)
+ {
+ case UnihanProperty.kSimplifiedVariant:
+ entry.SimplifiedVariant = char.ConvertFromUtf32(HexCodePoint.ParsePrefixed(reader.PropertyValue));
+ break;
+ case UnihanProperty.kTraditionalVariant:
+ entry.TraditionalVariant = char.ConvertFromUtf32(HexCodePoint.ParsePrefixed(reader.PropertyValue));
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+ }
+ }
+
+ private static async Task ProcessUnihanNumericValues(IDataSource unihanDataSource, UnicodeInfoBuilder builder)
+ {
+ using (var reader = new UnihanDataFileReader(await unihanDataSource.OpenDataFileAsync(UnihanNumericValuesFileName).ConfigureAwait(false)))
+ {
+ while (reader.Read())
+ {
+ var entry = builder.GetUnihan(reader.CodePoint);
+
+ switch (reader.PropertyName)
+ {
+ case UnihanProperty.kAccountingNumeric:
+ entry.NumericType = UnihanNumericType.Accounting;
+ break;
+ case UnihanProperty.kOtherNumeric:
+ entry.NumericType = UnihanNumericType.Other;
+ break;
+ case UnihanProperty.kPrimaryNumeric:
+ entry.NumericType = UnihanNumericType.Primary;
+ break;
+ default:
+ throw new InvalidDataException("Unrecognized property name: " + reader.PropertyName + ".");
+ }
+
+ entry.NumericValue = long.Parse(reader.PropertyValue);
+ }
+ }
+ }
}
}
diff --git a/UnicodeInformation.Builder/UnicodeInfoBuilder.cs b/UnicodeInformation.Builder/UnicodeInfoBuilder.cs
index 19027cb..b3ef64a 100644
--- a/UnicodeInformation.Builder/UnicodeInfoBuilder.cs
+++ b/UnicodeInformation.Builder/UnicodeInfoBuilder.cs
@@ -10,8 +10,10 @@ namespace System.Unicode.Builder
internal class UnicodeInfoBuilder
{
private readonly Version unicodeVersion;
- private UnicodeCharacterDataBuilder[] entries = new UnicodeCharacterDataBuilder[10000];
- private int entryCount;
+ private UnicodeCharacterDataBuilder[] ucdEntries = new UnicodeCharacterDataBuilder[10000];
+ private int ucdEntryCount;
+ private UnihanCharacterDataBuilder[] unihanEntries = new UnihanCharacterDataBuilder[10000];
+ private int unihanEntryCount;
private List blockEntries = new List(100);
public UnicodeInfoBuilder(Version unicodeVersion)
@@ -19,18 +21,18 @@ namespace System.Unicode.Builder
this.unicodeVersion = unicodeVersion;
}
- private int FindCodePoint(int codePoint)
+ private int FindUcdCodePoint(int codePoint)
{
- if (entryCount == 0) return -1;
+ if (ucdEntryCount == 0) return -1;
int minIndex = 0;
- int maxIndex = entryCount - 1;
+ int maxIndex = ucdEntryCount - 1;
do
{
int index = (minIndex + maxIndex) >> 1;
- int Δ = entries[index].CodePointRange.CompareCodePoint(codePoint);
+ int Δ = ucdEntries[index].CodePointRange.CompareCodePoint(codePoint);
if (Δ == 0) return index;
else if (Δ < 0) maxIndex = index - 1;
@@ -40,61 +42,144 @@ namespace System.Unicode.Builder
return -1;
}
- private int FindInsertionPoint(int startCodePoint, int endCodePoint)
+ private int FindUcdInsertionPoint(int startCodePoint, int endCodePoint)
{
int minIndex;
int maxIndex;
- if (entryCount == 0 || entries[maxIndex = entryCount - 1].CodePointRange.LastCodePoint < startCodePoint) return entryCount;
- else if (endCodePoint < entries[minIndex = 0].CodePointRange.FirstCodePoint) return 0;
- else if (entryCount == 1) return -1;
+ if (ucdEntryCount == 0 || ucdEntries[maxIndex = ucdEntryCount - 1].CodePointRange.LastCodePoint < startCodePoint) return ucdEntryCount;
+ else if (endCodePoint < ucdEntries[minIndex = 0].CodePointRange.FirstCodePoint) return 0;
+ else if (ucdEntryCount == 1) return -1;
do
{
int index = (minIndex + maxIndex) >> 1;
- int Δ = entries[index].CodePointRange.CompareCodePoint(startCodePoint);
+ int Δ = ucdEntries[index].CodePointRange.CompareCodePoint(startCodePoint);
if (Δ == 0) return -1;
else if (Δ < 0) maxIndex = index;
else minIndex = index;
} while (maxIndex - minIndex > 1);
- if (entries[maxIndex].CodePointRange.FirstCodePoint < endCodePoint) return -1;
+ if (ucdEntries[maxIndex].CodePointRange.FirstCodePoint < endCodePoint) return -1;
+ else return maxIndex;
+ }
+
+ private int FindUnihanCodePoint(int codePoint)
+ {
+ if (unihanEntryCount == 0) return -1;
+
+ int minIndex = 0;
+ int maxIndex = unihanEntryCount - 1;
+
+ do
+ {
+ int index = (minIndex + maxIndex) >> 1;
+
+ int Δ = codePoint - unihanEntries[index].CodePoint;
+
+ if (Δ == 0) return index;
+ else if (Δ < 0) maxIndex = index - 1;
+ else minIndex = index + 1;
+ } while (minIndex <= maxIndex);
+
+ return -1;
+ }
+
+ private int FindUnihanInsertionPoint(int codePoint)
+ {
+ int minIndex;
+ int maxIndex;
+
+ if (unihanEntryCount == 0 || unihanEntries[maxIndex = unihanEntryCount - 1].CodePoint < codePoint) return unihanEntryCount;
+ else if (codePoint < unihanEntries[minIndex = 0].CodePoint) return 0;
+ else if (unihanEntryCount == 1) return -1;
+
+ do
+ {
+ int index = (minIndex + maxIndex) >> 1;
+
+ int Δ = codePoint - unihanEntries[index].CodePoint;
+
+ if (Δ == 0) return -1;
+ else if (Δ < 0) maxIndex = index;
+ else minIndex = index;
+ } while (maxIndex - minIndex > 1);
+
+ if (unihanEntries[maxIndex].CodePoint < codePoint) return -1;
else return maxIndex;
}
public void Insert(UnicodeCharacterDataBuilder data)
{
- int insertionPoint = FindInsertionPoint(data.CodePointRange.FirstCodePoint, data.CodePointRange.LastCodePoint);
+ int insertionPoint = FindUcdInsertionPoint(data.CodePointRange.FirstCodePoint, data.CodePointRange.LastCodePoint);
if (insertionPoint < 0) throw new InvalidOperationException("The specified range overlaps with pre-existing ranges.");
- if (insertionPoint >= entries.Length)
+ if (insertionPoint >= ucdEntries.Length)
{
- Array.Resize(ref entries, entries.Length << 1);
+ Array.Resize(ref ucdEntries, ucdEntries.Length << 1);
}
- if (insertionPoint < entryCount)
+ if (insertionPoint < ucdEntryCount)
{
- Array.Copy(entries, insertionPoint, entries, insertionPoint + 1, entryCount - insertionPoint);
+ Array.Copy(ucdEntries, insertionPoint, ucdEntries, insertionPoint + 1, ucdEntryCount - insertionPoint);
}
- entries[insertionPoint] = data;
- ++entryCount;
+ ucdEntries[insertionPoint] = data;
+ ++ucdEntryCount;
}
- public UnicodeCharacterDataBuilder Get(int codePoint)
+ private void Insert(UnihanCharacterDataBuilder data)
{
- int index = FindCodePoint(codePoint);
+ int insertionPoint = FindUnihanInsertionPoint(data.CodePoint);
- return index >= 0 ? entries[index] : null;
+ if (insertionPoint < 0) throw new InvalidOperationException("The specified range overlaps with pre-existing ranges.");
+
+ if (insertionPoint >= unihanEntries.Length)
+ {
+ Array.Resize(ref unihanEntries, unihanEntries.Length << 1);
+ }
+
+ if (insertionPoint < unihanEntryCount)
+ {
+ Array.Copy(unihanEntries, insertionPoint, unihanEntries, insertionPoint + 1, unihanEntryCount - insertionPoint);
+ }
+
+ unihanEntries[insertionPoint] = data;
+ ++unihanEntryCount;
+ }
+
+ public UnicodeCharacterDataBuilder GetUcd(int codePoint)
+ {
+ int index = FindUcdCodePoint(codePoint);
+
+ return index >= 0 ? ucdEntries[index] : null;
+ }
+
+ public UnihanCharacterDataBuilder GetUnihan(int codePoint)
+ {
+ int index = FindUnihanCodePoint(codePoint);
+
+ if (index >= 0)
+ {
+ return unihanEntries[index];
+ }
+ else
+ {
+ var data = new UnihanCharacterDataBuilder(codePoint);
+
+ Insert(data);
+
+ return data;
+ }
}
public void SetProperties(ContributoryProperties property, UnicodeCharacterRange codePointRange)
{
- int firstIndex = FindCodePoint(codePointRange.FirstCodePoint);
- int lastIndex = FindCodePoint(codePointRange.LastCodePoint);
+ int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
+ int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
if (firstIndex < 0 && lastIndex < 0)
{
@@ -104,8 +189,8 @@ namespace System.Unicode.Builder
if (firstIndex < 0
|| lastIndex < 0
- || entries[firstIndex].CodePointRange.FirstCodePoint < codePointRange.FirstCodePoint
- || entries[lastIndex].CodePointRange.LastCodePoint > codePointRange.LastCodePoint)
+ || ucdEntries[firstIndex].CodePointRange.FirstCodePoint < codePointRange.FirstCodePoint
+ || ucdEntries[lastIndex].CodePointRange.LastCodePoint > codePointRange.LastCodePoint)
{
throw new InvalidOperationException();
}
@@ -114,7 +199,7 @@ namespace System.Unicode.Builder
while (true)
{
- entries[i].ContributoryProperties |= property;
+ ucdEntries[i].ContributoryProperties |= property;
if (i == lastIndex) break;
@@ -124,8 +209,8 @@ namespace System.Unicode.Builder
public void SetProperties(CoreProperties property, UnicodeCharacterRange codePointRange)
{
- int firstIndex = FindCodePoint(codePointRange.FirstCodePoint);
- int lastIndex = FindCodePoint(codePointRange.LastCodePoint);
+ int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
+ int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
if (firstIndex < 0 && lastIndex < 0)
{
@@ -135,8 +220,8 @@ namespace System.Unicode.Builder
if (firstIndex < 0
|| lastIndex < 0
- || entries[firstIndex].CodePointRange.FirstCodePoint < codePointRange.FirstCodePoint
- || entries[lastIndex].CodePointRange.LastCodePoint > codePointRange.LastCodePoint)
+ || ucdEntries[firstIndex].CodePointRange.FirstCodePoint < codePointRange.FirstCodePoint
+ || ucdEntries[lastIndex].CodePointRange.LastCodePoint > codePointRange.LastCodePoint)
{
throw new InvalidOperationException();
}
@@ -145,7 +230,7 @@ namespace System.Unicode.Builder
while (true)
{
- entries[i].CoreProperties |= property;
+ ucdEntries[i].CoreProperties |= property;
if (i == lastIndex) break;
@@ -160,12 +245,17 @@ namespace System.Unicode.Builder
public UnicodeInfo ToUnicodeData()
{
- var finalData = new UnicodeCharacterData[entryCount];
+ var finalUnicodeData = new UnicodeCharacterData[ucdEntryCount];
- for (int i = 0; i < finalData.Length; ++i)
- finalData[i] = entries[i].ToCharacterData();
+ for (int i = 0; i < finalUnicodeData.Length; ++i)
+ finalUnicodeData[i] = ucdEntries[i].ToCharacterData();
- return new UnicodeInfo(unicodeVersion, finalData, blockEntries.ToArray());
+ var finalUnihanData = new UnihanCharacterData[unihanEntryCount];
+
+ for (int i = 0; i < finalUnihanData.Length; ++i)
+ finalUnihanData[i] = unihanEntries[i].ToCharacterData();
+
+ return new UnicodeInfo(unicodeVersion, finalUnicodeData, finalUnihanData, blockEntries.ToArray());
}
private void WriteUnicodeBlockToFile(BinaryWriter writer, UnicodeBlock block)
@@ -182,15 +272,22 @@ namespace System.Unicode.Builder
writer.Write(new byte[] { (byte)'U', (byte)'C', (byte)'D', 0 });
writer.Write((ushort)7);
writer.Write((byte)0);
- writer.WriteCodePoint(entryCount);
- for (int i = 0; i < entryCount; ++i)
+ writer.WriteCodePoint(ucdEntryCount);
+ for (int i = 0; i < ucdEntryCount; ++i)
{
- entries[i].WriteToFile(writer);
+ ucdEntries[i].WriteToFile(writer);
}
if (blockEntries.Count > 255) throw new InvalidOperationException("There are too many block entries. The file format needs to be upgraded.");
writer.Write((byte)blockEntries.Count);
for (int i = 0; i < blockEntries.Count; ++i)
+ {
WriteUnicodeBlockToFile(writer, blockEntries[i]);
+ }
+ writer.WriteCodePoint(unihanEntryCount);
+ for (int i = 0; i < unihanEntryCount; ++i)
+ {
+ unihanEntries[i].WriteToFile(writer);
+ }
}
}
diff --git a/UnicodeInformation.Builder/UnicodeInformation.Builder.csproj b/UnicodeInformation.Builder/UnicodeInformation.Builder.csproj
index 1294119..1408e46 100644
--- a/UnicodeInformation.Builder/UnicodeInformation.Builder.csproj
+++ b/UnicodeInformation.Builder/UnicodeInformation.Builder.csproj
@@ -53,6 +53,15 @@
+
+ True
+ True
+ UnihanProperty.tt
+
+
+
+
+
@@ -77,6 +86,15 @@
UnicodeInformation
+
+
+ TextTemplatingFileGenerator
+ UnihanProperty.cs
+
+
+
+
+