2017-06-25 02:36:38 +02:00
|
|
|
using System.Collections.Generic;
|
2014-10-27 21:12:57 +01:00
|
|
|
using System.Globalization;
|
2014-11-03 03:44:41 +01:00
|
|
|
using System.IO;
|
2014-10-27 21:12:57 +01:00
|
|
|
using System.Linq;
|
|
|
|
|
|
2014-11-03 00:05:54 +01:00
|
|
|
namespace System.Unicode.Builder
|
2014-10-27 21:12:57 +01:00
|
|
|
{
|
|
|
|
|
public sealed class UnicodeCharacterDataBuilder
|
|
|
|
|
{
|
|
|
|
|
private UnicodeCategory category = UnicodeCategory.OtherNotAssigned;
|
|
|
|
|
|
2014-11-21 15:41:27 +01:00
|
|
|
private readonly List<UnicodeNameAlias> nameAliases = new List<UnicodeNameAlias>();
|
2014-11-24 00:24:55 +01:00
|
|
|
private readonly List<int> crossRerefences = new List<int>();
|
2014-10-27 21:12:57 +01:00
|
|
|
|
2017-06-25 02:36:38 +02:00
|
|
|
public UnicodeCodePointRange CodePointRange { get; }
|
2014-10-27 21:12:57 +01:00
|
|
|
|
2017-06-25 02:36:38 +02:00
|
|
|
public string Name { get; set; }
|
2014-10-27 21:12:57 +01:00
|
|
|
|
2014-11-24 20:09:59 +01:00
|
|
|
public IList<UnicodeNameAlias> NameAliases { get { return nameAliases; } }
|
2014-11-21 15:41:27 +01:00
|
|
|
|
2014-10-27 21:12:57 +01:00
|
|
|
public UnicodeCategory Category
|
|
|
|
|
{
|
2017-06-25 02:36:38 +02:00
|
|
|
get => category;
|
|
|
|
|
set => category = Enum.IsDefined(typeof(UnicodeCategory), value) ?
|
|
|
|
|
value :
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(value));
|
2014-11-08 22:00:12 +01:00
|
|
|
}
|
|
|
|
|
|
2017-06-25 02:36:38 +02:00
|
|
|
public CanonicalCombiningClass CanonicalCombiningClass { get; set; } // Even values not defined in the enum are allowed here.
|
|
|
|
|
public BidirectionalClass BidirectionalClass { get; set; }
|
|
|
|
|
public CharacterDecompositionMapping CharacterDecompositionMapping { get; set; }
|
|
|
|
|
public UnicodeNumericType NumericType { get; set; }
|
|
|
|
|
public UnicodeRationalNumber NumericValue { get; set; }
|
|
|
|
|
public string OldName { get; set; }
|
|
|
|
|
public bool BidirectionalMirrored { get; set; }
|
|
|
|
|
public string SimpleUpperCaseMapping { get; set; }
|
|
|
|
|
public string SimpleLowerCaseMapping { get; set; }
|
|
|
|
|
public string SimpleTitleCaseMapping { get; set; }
|
|
|
|
|
public ContributoryProperties ContributoryProperties { get; set; }
|
|
|
|
|
public CoreProperties CoreProperties { get; set; }
|
|
|
|
|
public EmojiProperties EmojiProperties { get; set; }
|
2014-11-24 20:09:59 +01:00
|
|
|
public IList<int> CrossRerefences { get { return crossRerefences; } }
|
2014-10-27 21:12:57 +01:00
|
|
|
|
|
|
|
|
public UnicodeCharacterDataBuilder(int codePoint)
|
2014-11-24 21:47:06 +01:00
|
|
|
: this(new UnicodeCodePointRange(codePoint))
|
2014-10-27 21:12:57 +01:00
|
|
|
{
|
2014-11-02 21:56:24 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-24 21:47:06 +01:00
|
|
|
public UnicodeCharacterDataBuilder(UnicodeCodePointRange codePointRange)
|
2014-11-02 21:56:24 +01:00
|
|
|
{
|
2017-06-25 02:36:38 +02:00
|
|
|
CodePointRange = codePointRange;
|
2014-11-02 21:56:24 +01:00
|
|
|
this.category = UnicodeCategory.OtherNotAssigned;
|
2014-10-27 21:12:57 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-07 23:40:00 +01:00
|
|
|
internal UnicodeCharacterData ToCharacterData()
|
2014-10-27 21:12:57 +01:00
|
|
|
{
|
|
|
|
|
return new UnicodeCharacterData
|
|
|
|
|
(
|
2014-11-21 15:41:27 +01:00
|
|
|
CodePointRange,
|
2014-10-27 21:12:57 +01:00
|
|
|
Name,
|
2017-06-25 02:36:38 +02:00
|
|
|
nameAliases.Count > 0 ? nameAliases.ToArray() : UnicodeNameAlias.EmptyArray,
|
2014-11-21 15:41:27 +01:00
|
|
|
Category,
|
|
|
|
|
CanonicalCombiningClass,
|
|
|
|
|
BidirectionalClass,
|
|
|
|
|
CharacterDecompositionMapping.DecompositionType,
|
|
|
|
|
CharacterDecompositionMapping.DecompositionMapping,
|
|
|
|
|
NumericType,
|
|
|
|
|
NumericValue,
|
|
|
|
|
BidirectionalMirrored,
|
|
|
|
|
OldName,
|
|
|
|
|
SimpleUpperCaseMapping,
|
|
|
|
|
SimpleLowerCaseMapping,
|
|
|
|
|
SimpleTitleCaseMapping,
|
|
|
|
|
ContributoryProperties,
|
2017-06-25 02:36:38 +02:00
|
|
|
(int)CoreProperties | (int)EmojiProperties << 20,
|
2014-11-24 00:24:55 +01:00
|
|
|
CrossRerefences.Count > 0 ? CrossRerefences.ToArray() : null
|
2014-10-27 21:12:57 +01:00
|
|
|
);
|
|
|
|
|
}
|
2014-11-03 03:44:41 +01:00
|
|
|
|
|
|
|
|
internal void WriteToFile(BinaryWriter writer)
|
|
|
|
|
{
|
2014-11-21 15:41:27 +01:00
|
|
|
if (nameAliases.Count > 64) throw new InvalidDataException("Cannot handle more than 64 name aliases.");
|
|
|
|
|
|
2014-11-03 03:44:41 +01:00
|
|
|
UcdFields fields = default(UcdFields);
|
|
|
|
|
|
2017-06-25 02:36:38 +02:00
|
|
|
if (!CodePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange;
|
2014-11-03 03:44:41 +01:00
|
|
|
|
2017-06-25 02:36:38 +02:00
|
|
|
if (Name != null || nameAliases.Count > 0) fields |= UcdFields.Name; // This field combines name and alias.
|
2014-11-03 03:44:41 +01:00
|
|
|
if (category != UnicodeCategory.OtherNotAssigned) fields |= UcdFields.Category;
|
2017-06-25 02:36:38 +02:00
|
|
|
if (CanonicalCombiningClass != CanonicalCombiningClass.NotReordered) fields |= UcdFields.CanonicalCombiningClass;
|
2014-11-16 21:27:57 +01:00
|
|
|
/*if (bidirectionalClass != 0)*/
|
|
|
|
|
fields |= UcdFields.BidirectionalClass;
|
2017-06-25 02:36:38 +02:00
|
|
|
if (CharacterDecompositionMapping.DecompositionMapping != null) fields |= UcdFields.DecompositionMapping;
|
|
|
|
|
fields |= (UcdFields)((int)NumericType << 6);
|
|
|
|
|
if (BidirectionalMirrored) fields |= UcdFields.BidirectionalMirrored;
|
|
|
|
|
if (OldName != null) fields |= UcdFields.OldName;
|
|
|
|
|
if (SimpleUpperCaseMapping != null) fields |= UcdFields.SimpleUpperCaseMapping;
|
|
|
|
|
if (SimpleLowerCaseMapping != null) fields |= UcdFields.SimpleLowerCaseMapping;
|
|
|
|
|
if (SimpleTitleCaseMapping != null) fields |= UcdFields.SimpleTitleCaseMapping;
|
|
|
|
|
if (ContributoryProperties != 0) fields |= UcdFields.ContributoryProperties;
|
|
|
|
|
if (CoreProperties != 0 || EmojiProperties != 0) fields |= UcdFields.CorePropertiesAndEmojiProperties;
|
2014-11-24 00:24:55 +01:00
|
|
|
if (crossRerefences.Count > 0) fields |= UcdFields.CrossRerefences;
|
2014-11-03 03:44:41 +01:00
|
|
|
|
|
|
|
|
writer.Write((ushort)fields);
|
|
|
|
|
|
2017-06-25 02:36:38 +02:00
|
|
|
writer.WriteCodePoint(CodePointRange.FirstCodePoint);
|
2014-11-03 03:44:41 +01:00
|
|
|
if ((fields & UcdFields.CodePointRange) != 0) writer.WriteCodePoint(CodePointRange.LastCodePoint);
|
|
|
|
|
|
2014-11-21 15:41:27 +01:00
|
|
|
if ((fields & UcdFields.Name) != 0)
|
|
|
|
|
{
|
|
|
|
|
// We write the names by optimizing for the common case.
|
2014-11-21 16:02:19 +01:00
|
|
|
// 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.
|
2014-11-21 15:41:27 +01:00
|
|
|
|
|
|
|
|
if (nameAliases.Count > 0)
|
|
|
|
|
{
|
2017-06-25 02:36:38 +02:00
|
|
|
writer.WritePackedLength((byte)(Name != null ? 3 : 2), nameAliases.Count);
|
2014-11-21 16:02:19 +01:00
|
|
|
|
2017-06-25 02:36:38 +02:00
|
|
|
if (Name != null)
|
|
|
|
|
writer.WriteNamePropertyToFile(Name);
|
2014-11-21 15:41:27 +01:00
|
|
|
|
|
|
|
|
foreach (var nameAlias in nameAliases)
|
|
|
|
|
writer.WriteNameAliasToFile(nameAlias);
|
|
|
|
|
}
|
2014-11-21 16:02:19 +01:00
|
|
|
else
|
|
|
|
|
{
|
2017-06-25 02:36:38 +02:00
|
|
|
writer.WriteNamePropertyToFile(Name);
|
2014-11-21 16:02:19 +01:00
|
|
|
}
|
2014-11-21 15:41:27 +01:00
|
|
|
}
|
2014-11-03 03:44:41 +01:00
|
|
|
if ((fields & UcdFields.Category) != 0) writer.Write((byte)category);
|
2017-06-25 02:36:38 +02:00
|
|
|
if ((fields & UcdFields.CanonicalCombiningClass) != 0) writer.Write((byte)CanonicalCombiningClass);
|
|
|
|
|
if ((fields & UcdFields.BidirectionalClass) != 0) writer.Write((byte)BidirectionalClass);
|
2014-11-07 01:05:40 +01:00
|
|
|
if ((fields & UcdFields.DecompositionMapping) != 0)
|
|
|
|
|
{
|
2017-06-25 02:36:38 +02:00
|
|
|
writer.Write((byte)CharacterDecompositionMapping.DecompositionType);
|
|
|
|
|
writer.Write(CharacterDecompositionMapping.DecompositionMapping);
|
2014-11-07 01:05:40 +01:00
|
|
|
}
|
2014-11-03 03:44:41 +01:00
|
|
|
if ((fields & UcdFields.NumericNumeric) != 0)
|
|
|
|
|
{
|
2017-06-25 02:36:38 +02:00
|
|
|
writer.Write(NumericValue.Numerator);
|
|
|
|
|
writer.Write(NumericValue.Denominator);
|
2014-11-03 03:44:41 +01:00
|
|
|
}
|
2017-06-25 02:36:38 +02:00
|
|
|
if ((fields & UcdFields.OldName) != 0) writer.Write(OldName);
|
|
|
|
|
if ((fields & UcdFields.SimpleUpperCaseMapping) != 0) writer.Write(SimpleUpperCaseMapping);
|
|
|
|
|
if ((fields & UcdFields.SimpleLowerCaseMapping) != 0) writer.Write(SimpleLowerCaseMapping);
|
|
|
|
|
if ((fields & UcdFields.SimpleTitleCaseMapping) != 0) writer.Write(SimpleTitleCaseMapping);
|
|
|
|
|
if ((fields & UcdFields.ContributoryProperties) != 0) writer.Write((int)ContributoryProperties);
|
|
|
|
|
if ((fields & UcdFields.CorePropertiesAndEmojiProperties) != 0) writer.WriteUInt24((int)CoreProperties | (int)EmojiProperties << 20);
|
2014-11-24 00:24:55 +01:00
|
|
|
if ((fields & UcdFields.CrossRerefences) != 0)
|
2014-11-23 18:44:32 +01:00
|
|
|
{
|
2014-11-24 00:24:55 +01:00
|
|
|
writer.Write(checked((byte)(crossRerefences.Count - 1)));
|
|
|
|
|
foreach (int crossReference in crossRerefences)
|
|
|
|
|
writer.WriteCodePoint(crossReference);
|
2014-11-23 18:44:32 +01:00
|
|
|
}
|
2014-11-03 03:44:41 +01:00
|
|
|
}
|
2014-10-27 21:12:57 +01:00
|
|
|
}
|
|
|
|
|
}
|