Files
NetUnicodeInfo/UnicodeInformation.Builder/UnicodeCharacterDataBuilder.cs
T
2014-11-21 15:41:27 +01:00

242 lines
7.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode.Builder
{
public sealed class UnicodeCharacterDataBuilder
{
private readonly UnicodeCharacterRange codePointRange;
private string name;
private UnicodeCategory category = UnicodeCategory.OtherNotAssigned;
private CanonicalCombiningClass canonicalCombiningClass;
private BidirectionalClass bidirectionalClass;
private CharacterDecompositionMapping characterDecompositionMapping;
private UnicodeNumericType numericType;
private UnicodeRationalNumber numericValue;
private bool bidirectionalMirrored;
private string oldName;
private string simpleUpperCaseMapping;
private string simpleLowerCaseMapping;
private string simpleTitleCaseMapping;
private ContributoryProperties contributoryProperties;
private CoreProperties coreProperties;
private readonly List<UnicodeNameAlias> nameAliases = new List<UnicodeNameAlias>();
private readonly List<int> relatedCodePoints = new List<int>();
public UnicodeCharacterRange CodePointRange { get { return codePointRange; } }
public string Name
{
get { return name; }
set { name = value; }
}
public ICollection<UnicodeNameAlias> NameAliases { get { return nameAliases; } }
public UnicodeCategory Category
{
get { return category; }
set
{
if (!Enum.IsDefined(typeof(UnicodeCategory), value))
{
throw new ArgumentOutOfRangeException("value");
}
category = value;
}
}
public CanonicalCombiningClass CanonicalCombiningClass
{
get { return canonicalCombiningClass; }
set { canonicalCombiningClass = value; } // Even values not defined in the enum are allowed here.
}
public BidirectionalClass BidirectionalClass
{
get { return bidirectionalClass; }
set { bidirectionalClass = value; }
}
public CharacterDecompositionMapping CharacterDecompositionMapping
{
get { return characterDecompositionMapping; }
set { characterDecompositionMapping = value; }
}
public UnicodeNumericType NumericType
{
get { return numericType; }
set { numericType = value; }
}
public UnicodeRationalNumber NumericValue
{
get { return numericValue; }
set { numericValue = value; }
}
public string OldName
{
get { return oldName; }
set { oldName = value; }
}
public bool BidirectionalMirrored
{
get { return bidirectionalMirrored; }
set { bidirectionalMirrored = value; }
}
public string SimpleUpperCaseMapping
{
get { return simpleUpperCaseMapping; }
set { simpleUpperCaseMapping = value; }
}
public string SimpleLowerCaseMapping
{
get { return simpleLowerCaseMapping; }
set { simpleLowerCaseMapping = value; }
}
public string SimpleTitleCaseMapping
{
get { return simpleTitleCaseMapping; }
set { simpleTitleCaseMapping = value; }
}
public ContributoryProperties ContributoryProperties
{
get { return contributoryProperties; }
set { contributoryProperties = value; }
}
public CoreProperties CoreProperties
{
get { return coreProperties; }
set { coreProperties = value; }
}
public ICollection<int> RelatedCodePoints { get { return relatedCodePoints; } }
public UnicodeCharacterDataBuilder(int codePoint)
: this(new UnicodeCharacterRange(codePoint))
{
}
public UnicodeCharacterDataBuilder(UnicodeCharacterRange codePointRange)
{
this.codePointRange = codePointRange;
this.category = UnicodeCategory.OtherNotAssigned;
}
internal UnicodeCharacterData ToCharacterData()
{
return new UnicodeCharacterData
(
CodePointRange,
Name,
NameAliases.Count > 0 ? NameAliases.ToArray() : UnicodeNameAlias.EmptyArray,
Category,
CanonicalCombiningClass,
BidirectionalClass,
CharacterDecompositionMapping.DecompositionType,
CharacterDecompositionMapping.DecompositionMapping,
NumericType,
NumericValue,
BidirectionalMirrored,
OldName,
SimpleUpperCaseMapping,
SimpleLowerCaseMapping,
SimpleTitleCaseMapping,
ContributoryProperties,
CoreProperties,
RelatedCodePoints.Count > 0 ? RelatedCodePoints.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 || 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 (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) fields |= UcdFields.CoreProperties;
writer.Write((ushort)fields);
writer.WriteCodePoint(codePointRange.FirstCodePoint);
if ((fields & UcdFields.CodePointRange) != 0) writer.WriteCodePoint(CodePointRange.LastCodePoint);
if ((fields & UcdFields.Name) != 0)
{
// We write the names by optimizing for the common case.
// i.e. Most characters have one name, and most of those characters have only one name.
// In the first byte, we will encode a 6bit length, along with two extra bits describing the structure:
// 00: The common case, this byte is the length of the name, and no other name follows.
// 01: This byte is the length of the name, and one alias follows.
// 10: This byte is the length of the name, and the number of aliases follows.
// 11: This byte is the number of aliases.
if (name == null)
{
writer.WritePackedLength(3, nameAliases.Count);
}
else
{
writer.WriteNameToFile((byte)(nameAliases.Count > 0 ? nameAliases.Count > 1 ? 2 : 1 : 0), name);
}
if (nameAliases.Count > 0)
{
if (name != null) writer.Write((byte)nameAliases.Count);
foreach (var nameAlias in nameAliases)
writer.WriteNameAliasToFile(nameAlias);
}
}
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);
if ((fields & UcdFields.DecompositionMapping) != 0)
{
writer.Write((byte)characterDecompositionMapping.DecompositionType);
writer.Write(characterDecompositionMapping.DecompositionMapping);
}
if ((fields & UcdFields.NumericNumeric) != 0)
{
writer.Write(numericValue.Numerator);
writer.Write(numericValue.Denominator);
}
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.CoreProperties) != 0) writer.WriteUInt24((int)coreProperties);
}
}
}