153 Commits

444 changed files with 13133 additions and 7636 deletions

View File

@@ -1,65 +0,0 @@
namespace Cryville.Common.Buffers {
/// <summary>
/// A resource pool that allows reusing instances of arrays of type <typeparamref name="T" />.
/// </summary>
/// <typeparam name="T">The item type of the arrays in the pool.</typeparam>
public class ArrayPool<T> {
private class Bucket : ObjectPool<T[]> {
readonly int _size;
public Bucket(int size, int capacity) : base(capacity) {
_size = size;
}
protected override T[] Construct() {
return new T[_size];
}
}
readonly Bucket[] _buckets;
/// <summary>
/// Creates an instance of the <see cref="ArrayPool{T}" /> class with the default maximum list size and bucket capacity.
/// </summary>
public ArrayPool() : this(0x40000000, 256) { }
/// <summary>
/// Creates an instance of the <see cref="ArrayPool{T}" /> class.
/// </summary>
/// <param name="maxSize">The maximum size of the arrays in the pool.</param>
/// <param name="capacityPerBucket">The capacity of each bucket. The pool groups arrays of similar sizes into buckets for faster access.</param>
public ArrayPool(int maxSize, int capacityPerBucket) {
if (maxSize < 16) maxSize = 16;
int num = GetID(maxSize) + 1;
_buckets = new Bucket[num];
for (int i = 0; i < num; i++) {
_buckets[i] = new Bucket(GetSize(i), capacityPerBucket);
}
}
/// <summary>
/// Rents an array that is at least the specified size from the pool.
/// </summary>
/// <param name="size">The minimum size of the array.</param>
/// <returns>An array of type <see cref="T" /> that is at least the specified size.</returns>
public T[] Rent(int size) {
int len2 = size;
if (len2 < 16) len2 = 16;
var arr = _buckets[GetID(len2)].Rent();
return arr;
}
/// <summary>
/// Returns a rented array to the pool.
/// </summary>
/// <param name="arr">The array to return.</param>
public void Return(T[] arr) {
int len2 = arr.Length;
if (len2 < 16) len2 = 16;
_buckets[GetID(len2)].Return(arr);
}
static int GetID(int size) {
size -= 1;
size >>= 4;
int num = 0;
for (; size != 0; size >>= 1) num++;
return num;
}
static int GetSize(int id) {
return 0x10 << id;
}
}
}

View File

@@ -1,90 +0,0 @@
using System.Collections.Generic;
namespace Cryville.Common.Buffers {
/// <summary>
/// A set of resource pools categorized by a category type.
/// </summary>
/// <typeparam name="TCategory">The category type.</typeparam>
/// <typeparam name="TObject">The type of the objects in the pool.</typeparam>
public abstract class CategorizedPool<TCategory, TObject> where TObject : class {
/// <summary>
/// The set of underlying pools.
/// </summary>
/// <remarks>
/// <para>The <see cref="Rent(TCategory)" /> and <see cref="Return(TCategory, TObject)" /> method select an underlying pool directly from this set with the category as the key. When overridden, this set must be available since construction.</para>
/// </remarks>
protected abstract IReadOnlyDictionary<TCategory, ObjectPool<TObject>> Buckets { get; }
/// <summary>
/// The count of objects rented from the set of pools.
/// </summary>
public int RentedCount { get; private set; }
/// <summary>
/// Rents an object from the pool.
/// </summary>
/// <param name="category">The category.</param>
/// <returns>The rented object.</returns>
public TObject Rent(TCategory category) {
var obj = Buckets[category].Rent();
RentedCount++;
return obj;
}
/// <summary>
/// Returns a rented object to the pool.
/// </summary>
/// <param name="category">The category.</param>
/// <param name="obj">The object to return.</param>
public void Return(TCategory category, TObject obj) {
Buckets[category].Return(obj);
--RentedCount;
}
}
/// <summary>
/// A utility to access a categorized pool, representing a single unit that uses a shared categorized pool.
/// </summary>
/// <typeparam name="TCategory">The category type.</typeparam>
/// <typeparam name="TObject">The type of the objects in the pool.</typeparam>
public class CategorizedPoolAccessor<TCategory, TObject> where TObject : class {
readonly CategorizedPool<TCategory, TObject> _pool;
static readonly SimpleObjectPool<Dictionary<TObject, TCategory>> _dictPool
= new SimpleObjectPool<Dictionary<TObject, TCategory>>(1024);
Dictionary<TObject, TCategory> _rented;
/// <summary>
/// Creates an instance of the <see cref="CategorizedPoolAccessor{TCategory, TObject}" /> class.
/// </summary>
/// <param name="pool">The categorized pool.</param>
public CategorizedPoolAccessor(CategorizedPool<TCategory, TObject> pool) {
_pool = pool;
}
/// <summary>
/// Rents an object from the pool.
/// </summary>
/// <param name="category">The category.</param>
/// <returns>The rented object.</returns>
public TObject Rent(TCategory category) {
var obj = _pool.Rent(category);
if (_rented == null) _rented = _dictPool.Rent();
_rented.Add(obj, category);
return obj;
}
/// <summary>
/// Returns a rented object to the pool.
/// </summary>
/// <param name="obj">The object to return.</param>
public void Return(TObject obj) {
_pool.Return(_rented[obj], obj);
_rented.Remove(obj);
}
/// <summary>
/// Returns all objects rented by this accessor to the pool.
/// </summary>
public void ReturnAll() {
if (_rented == null) return;
foreach (var obj in _rented) {
_pool.Return(obj.Value, obj.Key);
}
_rented.Clear();
_dictPool.Return(_rented);
_rented = null;
}
}
}

View File

@@ -1,71 +0,0 @@
using System.Collections.Generic;
namespace Cryville.Common.Buffers {
/// <summary>
/// A resource pool that allows reusing instances of lists of type <typeparamref name="T" />.
/// </summary>
/// <typeparam name="T">The item type of the lists in the pool.</typeparam>
public class ListPool<T> {
private class Bucket : ObjectPool<List<T>> {
readonly int _size;
public Bucket(int size, int capacity) : base(capacity) {
_size = size;
}
protected override List<T> Construct() {
return new List<T>(_size);
}
}
readonly Bucket[] _buckets;
/// <summary>
/// Creates an instance of the <see cref="ListPool{T}" /> class with the default maximum list size and bucket capacity.
/// </summary>
public ListPool() : this(0x40000000, 256) { }
/// <summary>
/// Creates an instance of the <see cref="ListPool{T}" /> class.
/// </summary>
/// <param name="maxSize">The maximum size of the lists in the pool.</param>
/// <param name="capacityPerBucket">The capacity of each bucket. The pool groups lists of similar sizes into buckets for faster access.</param>
public ListPool(int maxSize, int capacityPerBucket) {
if (maxSize < 16) maxSize = 16;
int num = GetID(maxSize) + 1;
_buckets = new Bucket[num];
for (int i = 0; i < num; i++) {
_buckets[i] = new Bucket(GetSize(i), capacityPerBucket);
}
}
/// <summary>
/// Rents a list of the specified size from the pool. The size of the list must not be changed when it is rented.
/// </summary>
/// <param name="size">The size of the list.</param>
/// <returns>A <see cref="List{T}" /> of the specified size.</returns>
public List<T> Rent(int size) {
int len2 = size;
if (len2 < 16) len2 = 16;
var list = _buckets[GetID(len2)].Rent();
if (list.Count < size)
for (int i = list.Count; i < size; i++) list.Add(default(T));
else if (list.Count > size)
list.RemoveRange(size, list.Count - size);
return list;
}
/// <summary>
/// Returns a rented list to the pool.
/// </summary>
/// <param name="list">The list to return.</param>
public void Return(List<T> list) {
int len2 = list.Capacity;
if (len2 < 16) len2 = 16;
_buckets[GetID(len2)].Return(list);
}
static int GetID(int size) {
size -= 1;
size >>= 4;
int num = 0;
for (; size != 0; size >>= 1) num++;
return num;
}
static int GetSize(int id) {
return 0x10 << id;
}
}
}

View File

@@ -1,54 +0,0 @@
namespace Cryville.Common.Buffers {
/// <summary>
/// A resource pool that allows reusing instances of type <typeparamref name="T" />.
/// </summary>
/// <typeparam name="T">The type of the objects in the pool.</typeparam>
public abstract class ObjectPool<T> where T : class {
int _index;
readonly T[] _objs;
/// <summary>
/// Creates an instance of the <see cref="ObjectPool{T}" /> class.
/// </summary>
/// <param name="capacity">The capacity of the pool.</param>
public ObjectPool(int capacity) {
_objs = new T[capacity];
}
/// <summary>
/// The count of objects rented from the pool.
/// </summary>
public int RentedCount { get { return _index; } }
/// <summary>
/// Rents a object from the pool.
/// </summary>
/// <returns>The rented object.</returns>
public T Rent() {
T obj = null;
if (_index < _objs.Length) {
obj = _objs[_index];
_objs[_index++] = null;
}
if (obj == null) obj = Construct();
return obj;
}
/// <summary>
/// Returns a rented object to the pool.
/// </summary>
/// <param name="obj">The object to return.</param>
public void Return(T obj) {
if (_index > 0) {
Reset(obj);
_objs[--_index] = obj;
}
}
/// <summary>
/// Constructs a new instance of type <typeparamref name="T" />.
/// </summary>
/// <returns>The new instance.</returns>
protected abstract T Construct();
/// <summary>
/// Resets an object.
/// </summary>
/// <param name="obj">The object.</param>
protected virtual void Reset(T obj) { }
}
}

View File

@@ -1,16 +0,0 @@
namespace Cryville.Common.Buffers {
/// <summary>
/// A resource pool that allows reusing instances of type <typeparamref name="T" />, which has a parameterless constructor.
/// </summary>
/// <typeparam name="T">The type of the objects in the pool.</typeparam>
public class SimpleObjectPool<T> : ObjectPool<T> where T : class, new() {
/// <summary>
/// Creates an instance of the <see cref="SimpleObjectPool{T}" /> class.
/// </summary>
/// <param name="capacity">The capacity of the pool.</param>
public SimpleObjectPool(int capacity) : base(capacity) { }
protected override T Construct() {
return new T();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: b8cd439340f088d4eb83711a5bc6384d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,135 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Cryville.Common.Buffers {
/// <summary>
/// An auto-resized <see cref="char" /> array as a variable-length string used as a target that is modified frequently.
/// </summary>
public class TargetString : IEnumerable<char> {
public event Action OnUpdate;
char[] _arr;
bool _invalidated;
/// <summary>
/// Creates an instance of the <see cref="TargetString" /> class with a capacity of 16.
/// </summary>
public TargetString() : this(16) { }
/// <summary>
/// Creates an instance of the <see cref="TargetString" /> class.
/// </summary>
/// <param name="capacity">The initial capacity of the string.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity" /> is less than or equal to 0.</exception>
public TargetString(int capacity) {
if (capacity <= 0) throw new ArgumentOutOfRangeException("capacity");
_arr = new char[capacity];
}
/// <summary>
/// Gets or sets one of the characters in the string.
/// </summary>
/// <param name="index">The zero-based index of the character.</param>
/// <returns>The character at the given index.</returns>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index" /> is less than 0 or not less than <see cref="Length" />.</exception>
/// <remarks>
/// <para>Set <see cref="Length" /> to a desired value before updating the characters.</para>
/// <para>Call <see cref=" Validate" /> after all the characters are updated.</para>
/// </remarks>
public char this[int index] {
get {
if (index < 0 || index >= m_length)
throw new ArgumentOutOfRangeException("index");
return _arr[index];
}
set {
if (index < 0 || index >= m_length)
throw new ArgumentOutOfRangeException("index");
if (_arr[index] == value) return;
_arr[index] = value;
_invalidated = true;
}
}
int m_length;
/// <summary>
/// The length of the string.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">The value specified for a set operation is less than 0.</exception>
public int Length {
get {
return m_length;
}
set {
if (Length < 0) throw new ArgumentOutOfRangeException("length");
if (m_length == value) return;
if (_arr.Length < value) {
var len = _arr.Length;
while (len < value) len *= 2;
var arr2 = new char[len];
Array.Copy(_arr, arr2, m_length);
_arr = arr2;
}
m_length = value;
_invalidated = true;
}
}
/// <summary>
/// Validates the string.
/// </summary>
public void Validate() {
if (!_invalidated) return;
_invalidated = false;
var ev = OnUpdate;
if (ev != null) ev.Invoke();
}
internal char[] TrustedAsArray() { return _arr; }
/// <summary>
/// Returns an enumerator that iterates through the <see cref="TargetString" />.
/// </summary>
/// <returns>A <see cref="Enumerator" /> for the <see cref="TargetString" />.</returns>
public Enumerator GetEnumerator() {
return new Enumerator(this);
}
IEnumerator<char> IEnumerable<char>.GetEnumerator() {
return new Enumerator(this);
}
IEnumerator IEnumerable.GetEnumerator() {
return new Enumerator(this);
}
public struct Enumerator : IEnumerator<char> {
readonly TargetString _self;
int _index;
internal Enumerator(TargetString self) {
_self = self;
_index = -1;
}
public char Current {
get {
if (_index < 0)
throw new InvalidOperationException(_index == -1 ? "Enum not started" : "Enum ended");
return _self[_index];
}
}
object IEnumerator.Current { get { return Current; } }
public void Dispose() {
_index = -2;
}
public bool MoveNext() {
if (_index == -2) return false;
_index++;
if (_index >= _self.Length) {
_index = -2;
return false;
}
return true;
}
public void Reset() {
_index = -1;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f0fc34ac257793d4883a9cfcdb6941b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
using System.Collections.Generic;
namespace Cryville.Common.Collections.Generic {
public interface IPairList<TKey, TValue> : IList<KeyValuePair<TKey, TValue>> {
void Add(TKey key, TValue value);
void Insert(int index, TKey key, TValue value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 73fb17b484b343242bcce27c15ed7d44
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,50 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Cryville.Common.Collections.Generic {
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(PairCollectionDebugView<,>))]
public struct PairCollection<TKey, TValue> : IDisposable {
public void Dispose() { }
readonly IPairList<TKey, TValue> _pairList;
readonly IDictionary<TKey, TValue> _dictionary;
public PairCollection(object collection) : this() {
var type = collection.GetType();
if (typeof(IPairList<TKey, TValue>).IsAssignableFrom(type)) _pairList = (IPairList<TKey, TValue>)collection;
else if (typeof(IDictionary<TKey, TValue>).IsAssignableFrom(type)) _dictionary = (IDictionary<TKey, TValue>)collection;
else throw new ArgumentException("Parameter is not a pair collection");
}
public int Count {
get {
if (_pairList != null) return _pairList.Count;
else return _dictionary.Count;
}
}
public void Add(TKey key, TValue value) {
if (_pairList != null) _pairList.Add(key, value);
else _dictionary.Add(key, value);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index) {
if (_pairList != null) _pairList.CopyTo(array, index);
else _dictionary.CopyTo(array, index);
}
public static bool IsPairCollection(Type type) {
return typeof(IPairList<TKey, TValue>).IsAssignableFrom(type) || typeof(IDictionary<TKey, TValue>).IsAssignableFrom(type);
}
}
internal class PairCollectionDebugView<TKey, TValue> {
readonly PairCollection<TKey, TValue> _self;
public PairCollectionDebugView(PairCollection<TKey, TValue> self) {
_self = self;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<TKey, TValue>[] Items {
get {
KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[_self.Count];
_self.CopyTo(array, 0);
return array;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2517e8f040bd36f46948e5fafaf5335c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,48 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Cryville.Common.Collections.Generic {
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(PairListDebugView<,>))]
public class PairList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>, IPairList<TKey, TValue>, IPairList {
public void Add(TKey key, TValue value) {
Add(new KeyValuePair<TKey, TValue>(key, value));
}
public void Add(object key, object value) {
try {
Add((TKey)key, (TValue)value);
}
catch (InvalidCastException) {
throw new ArgumentException("Wrong key type or value type");
}
}
public void Insert(int index, TKey key, TValue value) {
Insert(index, new KeyValuePair<TKey, TValue>(key, value));
}
public void Insert(int index, object key, object value) {
try {
Insert(index, (TKey)key, (TValue)value);
}
catch (InvalidCastException) {
throw new ArgumentException("Wrong key type or value type");
}
}
}
internal class PairListDebugView<TKey, TValue> {
readonly PairList<TKey, TValue> _self;
public PairListDebugView(PairList<TKey, TValue> self) {
_self = self;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<TKey, TValue>[] Items {
get {
KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[_self.Count];
_self.CopyTo(array, 0);
return array;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d9ed5ea8b7b1a934287e7ec5971166c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,106 +0,0 @@
using System;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.Serialization;
using System.Threading;
namespace Cryville.Common.Collections {
internal static class HashHelpers {
#if FEATURE_RANDOMIZED_STRING_HASHING
public const int HashCollisionThreshold = 100;
public static bool s_UseRandomizedStringHashing = String.UseRandomizedHashing();
#endif
// Table of prime numbers to use as hash table sizes.
// A typical resize algorithm would pick the smallest prime number in this array
// that is larger than twice the previous capacity.
// Suppose our Hashtable currently has capacity x and enough elements are added
// such that a resize needs to occur. Resizing first computes 2x then finds the
// first prime in the table greater than 2x, i.e. if primes are ordered
// p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n.
// Doubling is important for preserving the asymptotic complexity of the
// hashtable operations such as add. Having a prime guarantees that double
// hashing does not lead to infinite loops. IE, your hash function will be
// h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
public static readonly int[] primes = {
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
// Used by Hashtable and Dictionary's SeralizationInfo .ctor's to store the SeralizationInfo
// object until OnDeserialization is called.
private static ConditionalWeakTable<object, SerializationInfo> s_SerializationInfoTable;
internal static ConditionalWeakTable<object, SerializationInfo> SerializationInfoTable {
get {
if (s_SerializationInfoTable == null) {
ConditionalWeakTable<object, SerializationInfo> newTable = new ConditionalWeakTable<object, SerializationInfo>();
Interlocked.CompareExchange(ref s_SerializationInfoTable, newTable, null);
}
return s_SerializationInfoTable;
}
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static bool IsPrime(int candidate) {
if ((candidate & 1) != 0) {
int limit = (int)System.Math.Sqrt (candidate);
for (int divisor = 3; divisor <= limit; divisor += 2) {
if ((candidate % divisor) == 0)
return false;
}
return true;
}
return (candidate == 2);
}
internal const Int32 HashPrime = 101;
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static int GetPrime(int min) {
if (min < 0)
throw new ArgumentException("Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table.");
Contract.EndContractBlock();
for (int i = 0; i < primes.Length; i++) {
int prime = primes[i];
if (prime >= min) return prime;
}
//outside of our predefined table.
//compute the hard way.
for (int i = (min | 1); i < Int32.MaxValue; i += 2) {
if (IsPrime(i) && ((i - 1) % HashPrime != 0))
return i;
}
return min;
}
public static int GetMinPrime() {
return primes[0];
}
// Returns size of hashtable to grow to.
public static int ExpandPrime(int oldSize) {
int newSize = 2 * oldSize;
// Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize) {
Contract.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
return MaxPrimeArrayLength;
}
return GetPrime(newSize);
}
// This is the maximum prime smaller than Array.MaxArrayLength
public const int MaxPrimeArrayLength = 0x7FEFFFFD;
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e7fe2c6f3299681448c1a546cce4dc65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
using System.Collections;
namespace Cryville.Common.Collections {
public interface IPairList : IList {
void Add(object key, object value);
void Insert(int index, object key, object value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 046617672d437de4ab7e644a55defd3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,51 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Cryville.Common.Collections {
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(PairCollectionDebugView))]
public struct PairCollection : IDisposable {
public void Dispose() { }
readonly IPairList _pairList;
readonly IDictionary _dictionary;
public PairCollection(object collection) : this() {
var type = collection.GetType();
if (typeof(IPairList).IsAssignableFrom(type)) _pairList = (IPairList)collection;
else if (typeof(IDictionary).IsAssignableFrom(type)) _dictionary = (IDictionary)collection;
else throw new ArgumentException("Parameter is not a pair collection");
}
public int Count {
get {
if (_pairList != null) return _pairList.Count;
else return _dictionary.Count;
}
}
public void Add(object key, object value) {
if (_pairList != null) _pairList.Add(key, value);
else _dictionary.Add(key, value);
}
public void CopyTo(KeyValuePair<object, object>[] array, int index) {
if (_pairList != null) _pairList.CopyTo(array, index);
else _dictionary.CopyTo(array, index);
}
public static bool IsPairCollection(Type type) {
return typeof(IPairList).IsAssignableFrom(type) || typeof(IDictionary).IsAssignableFrom(type);
}
}
internal class PairCollectionDebugView {
readonly PairCollection _self;
public PairCollectionDebugView(PairCollection self) {
_self = self;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<object, object>[] Items {
get {
KeyValuePair<object, object>[] array = new KeyValuePair<object, object>[_self.Count];
_self.CopyTo(array, 0);
return array;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 1f87dfb8f6a1f5640b6deae741cd715c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,29 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace Cryville.Common.Collections {
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(PairListDebugView))]
public class PairList : List<KeyValuePair<object, object>>, IPairList {
public void Add(object key, object value) {
Add(new KeyValuePair<object, object>(key, value));
}
public void Insert(int index, object key, object value) {
Insert(index, new KeyValuePair<object, object>(key, value));
}
}
internal class PairListDebugView {
readonly PairList _self;
public PairListDebugView(PairList self) {
_self = self;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<object, object>[] Items {
get {
KeyValuePair<object, object>[] array = new KeyValuePair<object, object>[_self.Count];
_self.CopyTo(array, 0);
return array;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 57fc9f037c1fda5449e2a365a835c82c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 634536d804abc784394d4ac028a77879
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,12 +3,12 @@ using System;
namespace Cryville.Common.ComponentModel { namespace Cryville.Common.ComponentModel {
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class RangeAttribute : Attribute { public class RangeAttribute : Attribute {
public RangeAttribute(float min, float max) { public RangeAttribute(double min, double max) {
Min = min; Min = min;
Max = max; Max = max;
} }
public float Min { get; set; } public double Min { get; set; }
public float Max { get; set; } public double Max { get; set; }
} }
} }

View File

@@ -3,9 +3,9 @@ using System;
namespace Cryville.Common.ComponentModel { namespace Cryville.Common.ComponentModel {
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class StepAttribute : Attribute { public class StepAttribute : Attribute {
public StepAttribute(float step) { public StepAttribute(double step) {
Step = step; Step = step;
} }
public float Step { get; set; } public double Step { get; set; }
} }
} }

View File

@@ -6,295 +6,295 @@ using System.Linq;
namespace Cryville.Common.Font { namespace Cryville.Common.Font {
public abstract class FontMatcher { public abstract class FontMatcher {
protected FontManager Manager { get; private set; } protected FontManager Manager { get; private set; }
public FontMatcher(FontManager manafer) { Manager = manafer; } public FontMatcher(FontManager manager) { Manager = manager; }
public abstract IEnumerable<Typeface> MatchScript(string script = null, bool distinctFamily = false); public abstract IEnumerable<Typeface> MatchScript(string script = null, bool distinctFamily = false);
} }
public class FallbackListFontMatcher : FontMatcher { public class FallbackListFontMatcher : FontMatcher {
public Dictionary<string, List<string>> MapScriptToTypefaces = new Dictionary<string, List<string>>(); public Dictionary<string, List<string>> MapScriptToTypefaces = new Dictionary<string, List<string>>();
public void LoadDefaultWindowsFallbackList() { public static Dictionary<string, List<string>> GetDefaultWindowsFallbackMap() {
if (Environment.OSVersion.Platform != PlatformID.Win32NT) return; var map = new Dictionary<string, List<string>>();
MapScriptToTypefaces.Clear(); ScriptUtils.FillKeysWithScripts(map, () => new List<string>());
ScriptUtils.FillKeysWithScripts(MapScriptToTypefaces, () => new List<string>());
// Reference: https://github.com/chromium/chromium/blob/main/third_party/blink/renderer/platform/fonts/win/font_fallback_win.cc // Reference: https://github.com/chromium/chromium/blob/main/third_party/blink/renderer/platform/fonts/win/font_fallback_win.cc
MapScriptToTypefaces["zyyy"].Insert(0, "SimSun"); // Custom map["zyyy"].Insert(0, "SimSun"); // Custom
MapScriptToTypefaces["zyyy"].Insert(0, "SimHei"); // Custom map["zyyy"].Insert(0, "SimHei"); // Custom
MapScriptToTypefaces["zyyy"].Insert(0, "Microsoft YaHei"); // Custom map["zyyy"].Insert(0, "Microsoft YaHei"); // Custom
MapScriptToTypefaces["zyyy"].Insert(0, "Arial"); map["zyyy"].Insert(0, "Arial");
MapScriptToTypefaces["zyyy"].Insert(0, "Times New Roman"); map["zyyy"].Insert(0, "Times New Roman");
MapScriptToTypefaces["zyyy"].Insert(0, "Segoe UI"); // Custom map["zyyy"].Insert(0, "Segoe UI"); // Custom
MapScriptToTypefaces["arab"].Insert(0, "Tahoma"); map["arab"].Insert(0, "Tahoma");
MapScriptToTypefaces["cyrl"].Insert(0, "Times New Roman"); map["cyrl"].Insert(0, "Times New Roman");
MapScriptToTypefaces["grek"].Insert(0, "Times New Roman"); map["grek"].Insert(0, "Times New Roman");
MapScriptToTypefaces["hebr"].Insert(0, "David"); map["hebr"].Insert(0, "David");
MapScriptToTypefaces["jpan"].Insert(0, "MS PGothic"); map["jpan"].Insert(0, "MS PGothic");
MapScriptToTypefaces["latn"].Insert(0, "Times New Roman"); map["latn"].Insert(0, "Times New Roman");
MapScriptToTypefaces["hans"].Insert(0, "SimSun"); map["hans"].Insert(0, "SimSun");
MapScriptToTypefaces["hans"].Insert(0, "SimHei"); // Custom map["hans"].Insert(0, "SimHei"); // Custom
MapScriptToTypefaces["thai"].Insert(0, "Tahoma"); map["thai"].Insert(0, "Tahoma");
MapScriptToTypefaces["hans"].Insert(0, "PMingLiU"); map["hans"].Insert(0, "PMingLiU");
// Reference: https://learn.microsoft.com/en-us/globalization/input/font-support // Reference: https://learn.microsoft.com/en-us/globalization/input/font-support
var ver = Environment.OSVersion.Version; var ver = Environment.OSVersion.Version;
if (ver >= new Version(5, 0)) { // Windows 2000 if (ver >= new Version(5, 0)) { // Windows 2000
MapScriptToTypefaces["armn"].Insert(0, "Sylfaen"); map["armn"].Insert(0, "Sylfaen");
MapScriptToTypefaces["deva"].Insert(0, "Mangal"); map["deva"].Insert(0, "Mangal");
MapScriptToTypefaces["geor"].Insert(0, "Sylfaen"); map["geor"].Insert(0, "Sylfaen");
MapScriptToTypefaces["taml"].Insert(0, "Latha"); map["taml"].Insert(0, "Latha");
} }
if (ver >= new Version(5, 1)) { // Windows XP if (ver >= new Version(5, 1)) { // Windows XP
MapScriptToTypefaces["gujr"].Insert(0, "Shruti"); map["gujr"].Insert(0, "Shruti");
MapScriptToTypefaces["guru"].Insert(0, "Raavi"); map["guru"].Insert(0, "Raavi");
MapScriptToTypefaces["knda"].Insert(0, "Tunga"); map["knda"].Insert(0, "Tunga");
MapScriptToTypefaces["syrc"].Insert(0, "Estrangelo Edessa"); map["syrc"].Insert(0, "Estrangelo Edessa");
MapScriptToTypefaces["telu"].Insert(0, "Gautami"); map["telu"].Insert(0, "Gautami");
MapScriptToTypefaces["thaa"].Insert(0, "MV Boli"); map["thaa"].Insert(0, "MV Boli");
// SP2 // SP2
MapScriptToTypefaces["beng"].Insert(0, "Vrinda"); map["beng"].Insert(0, "Vrinda");
MapScriptToTypefaces["mlym"].Insert(0, "Kartika"); map["mlym"].Insert(0, "Kartika");
} }
if (ver >= new Version(6, 0)) { // Windows Vista if (ver >= new Version(6, 0)) { // Windows Vista
MapScriptToTypefaces["cans"].Insert(0, "Euphemia"); map["cans"].Insert(0, "Euphemia");
MapScriptToTypefaces["cher"].Insert(0, "Plantagenet"); map["cher"].Insert(0, "Plantagenet");
MapScriptToTypefaces["ethi"].Insert(0, "Nyala"); map["ethi"].Insert(0, "Nyala");
MapScriptToTypefaces["khmr"].Insert(0, "DaunPenh MoolBoran"); map["khmr"].Insert(0, "DaunPenh MoolBoran");
MapScriptToTypefaces["laoo"].Insert(0, "DokChampa"); map["laoo"].Insert(0, "DokChampa");
MapScriptToTypefaces["mong"].Insert(0, "Mongolian Baiti"); map["mong"].Insert(0, "Mongolian Baiti");
MapScriptToTypefaces["orya"].Insert(0, "Kalinga"); map["orya"].Insert(0, "Kalinga");
MapScriptToTypefaces["sinh"].Insert(0, "Iskoola Pota"); map["sinh"].Insert(0, "Iskoola Pota");
MapScriptToTypefaces["tibt"].Insert(0, "Microsoft Himalaya"); map["tibt"].Insert(0, "Microsoft Himalaya");
MapScriptToTypefaces["yiii"].Insert(0, "Microsoft Yi Baiti"); map["yiii"].Insert(0, "Microsoft Yi Baiti");
MapScriptToTypefaces["arab"].Insert(0, "Segoe UI"); map["arab"].Insert(0, "Segoe UI");
MapScriptToTypefaces["cyrl"].Insert(0, "Segoe UI"); map["cyrl"].Insert(0, "Segoe UI");
MapScriptToTypefaces["grek"].Insert(0, "Segoe UI"); map["grek"].Insert(0, "Segoe UI");
MapScriptToTypefaces["latn"].Insert(0, "Segoe UI"); map["latn"].Insert(0, "Segoe UI");
MapScriptToTypefaces["hans"].Add("SimSun-ExtB"); map["hans"].Add("SimSun-ExtB");
MapScriptToTypefaces["hant"].Add("MingLiU-ExtB"); map["hant"].Add("MingLiU-ExtB");
MapScriptToTypefaces["hant"].Add("MingLiU_HKSCS-ExtB"); map["hant"].Add("MingLiU_HKSCS-ExtB");
MapScriptToTypefaces["arab"].Add("Microsoft Uighur"); map["arab"].Add("Microsoft Uighur");
MapScriptToTypefaces["zmth"].Insert(0, "Cambria Math"); map["zmth"].Insert(0, "Cambria Math");
// Reference: https://en.wikipedia.org/wiki/List_of_CJK_fonts // Reference: https://en.wikipedia.org/wiki/List_of_CJK_fonts
MapScriptToTypefaces["jpan"].Insert(0, "Meiryo"); map["jpan"].Insert(0, "Meiryo");
MapScriptToTypefaces["hans"].Insert(0, "Microsoft YaHei"); map["hans"].Insert(0, "Microsoft YaHei");
} }
if (ver >= new Version(6, 1)) { // Windows 7 if (ver >= new Version(6, 1)) { // Windows 7
MapScriptToTypefaces["brai"].Insert(0, "Segoe UI Symbol"); map["brai"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["dsrt"].Insert(0, "Segoe UI Symbol"); map["dsrt"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["talu"].Insert(0, "Microsoft New Tai Lue"); map["talu"].Insert(0, "Microsoft New Tai Lue");
MapScriptToTypefaces["ogam"].Insert(0, "Segoe UI Symbol"); map["ogam"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["osma"].Insert(0, "Ebrima"); map["osma"].Insert(0, "Ebrima");
MapScriptToTypefaces["phag"].Insert(0, "Microsoft PhagsPa"); map["phag"].Insert(0, "Microsoft PhagsPa");
MapScriptToTypefaces["runr"].Insert(0, "Segoe UI Symbol"); map["runr"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["zsym"].Insert(0, "Segoe UI Symbol"); map["zsym"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["tale"].Insert(0, "Microsoft Tai Le"); map["tale"].Insert(0, "Microsoft Tai Le");
MapScriptToTypefaces["tfng"].Insert(0, "Ebrima"); map["tfng"].Insert(0, "Ebrima");
MapScriptToTypefaces["vaii"].Insert(0, "Ebrima"); map["vaii"].Insert(0, "Ebrima");
} }
if (ver >= new Version(6, 2)) { // Windows 8 if (ver >= new Version(6, 2)) { // Windows 8
MapScriptToTypefaces["glag"].Insert(0, "Segoe UI Symbol"); map["glag"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["goth"].Insert(0, "Segoe UI Symbol"); map["goth"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["hang"].Add("Malgun Gothic"); map["hang"].Add("Malgun Gothic");
MapScriptToTypefaces["ital"].Insert(0, "Segoe UI Symbol"); map["ital"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["lisu"].Insert(0, "Segoe UI"); map["lisu"].Insert(0, "Segoe UI");
MapScriptToTypefaces["mymr"].Insert(0, "Myanmar Text"); map["mymr"].Insert(0, "Myanmar Text");
MapScriptToTypefaces["nkoo"].Insert(0, "Ebrima"); map["nkoo"].Insert(0, "Ebrima");
MapScriptToTypefaces["orkh"].Insert(0, "Segoe UI Symbol"); map["orkh"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["ethi"].Insert(0, "Ebrima"); map["ethi"].Insert(0, "Ebrima");
MapScriptToTypefaces["cans"].Insert(0, "Gadugi"); map["cans"].Insert(0, "Gadugi");
MapScriptToTypefaces["hant"].Insert(0, "Microsoft JhengHei UI"); map["hant"].Insert(0, "Microsoft JhengHei UI");
MapScriptToTypefaces["hans"].Insert(0, "Microsoft YaHei UI"); map["hans"].Insert(0, "Microsoft YaHei UI");
MapScriptToTypefaces["beng"].Insert(0, "Nirmala UI"); map["beng"].Insert(0, "Nirmala UI");
MapScriptToTypefaces["deva"].Insert(0, "Nirmala UI"); map["deva"].Insert(0, "Nirmala UI");
MapScriptToTypefaces["gujr"].Insert(0, "Nirmala UI"); map["gujr"].Insert(0, "Nirmala UI");
MapScriptToTypefaces["guru"].Insert(0, "Nirmala UI"); // NOT DOCUMENTED, UNVERIFIED map["guru"].Insert(0, "Nirmala UI"); // NOT DOCUMENTED, UNVERIFIED
MapScriptToTypefaces["knda"].Insert(0, "Nirmala UI"); // NOT DOCUMENTED, UNVERIFIED map["knda"].Insert(0, "Nirmala UI"); // NOT DOCUMENTED, UNVERIFIED
MapScriptToTypefaces["mlym"].Insert(0, "Nirmala UI"); map["mlym"].Insert(0, "Nirmala UI");
MapScriptToTypefaces["orya"].Insert(0, "Nirmala UI"); map["orya"].Insert(0, "Nirmala UI");
MapScriptToTypefaces["sinh"].Insert(0, "Nirmala UI"); // NOT DOCUMENTED, UNVERIFIED map["sinh"].Insert(0, "Nirmala UI"); // NOT DOCUMENTED, UNVERIFIED
MapScriptToTypefaces["taml"].Insert(0, "Nirmala UI"); // NOT DOCUMENTED, UNVERIFIED map["taml"].Insert(0, "Nirmala UI"); // NOT DOCUMENTED, UNVERIFIED
MapScriptToTypefaces["telu"].Insert(0, "Nirmala UI"); map["telu"].Insert(0, "Nirmala UI");
MapScriptToTypefaces["armn"].Insert(0, "Segoe UI"); map["armn"].Insert(0, "Segoe UI");
MapScriptToTypefaces["geor"].Insert(0, "Segoe UI"); map["geor"].Insert(0, "Segoe UI");
MapScriptToTypefaces["hebr"].Insert(0, "Segoe UI"); map["hebr"].Insert(0, "Segoe UI");
} }
if (ver >= new Version(6, 3)) { // Windows 8.1 if (ver >= new Version(6, 3)) { // Windows 8.1
MapScriptToTypefaces["bugi"].Insert(0, "Leelawadee UI"); map["bugi"].Insert(0, "Leelawadee UI");
MapScriptToTypefaces["copt"].Insert(0, "Segoe UI Symbol"); map["copt"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["java"].Insert(0, "Javanese Text"); map["java"].Insert(0, "Javanese Text");
MapScriptToTypefaces["merc"].Insert(0, "Segoe UI Symbol"); map["merc"].Insert(0, "Segoe UI Symbol");
MapScriptToTypefaces["olck"].Insert(0, "Nirmala UI"); map["olck"].Insert(0, "Nirmala UI");
MapScriptToTypefaces["sora"].Insert(0, "Nirmala UI"); map["sora"].Insert(0, "Nirmala UI");
MapScriptToTypefaces["khmr"].Insert(0, "Leelawadee UI"); map["khmr"].Insert(0, "Leelawadee UI");
MapScriptToTypefaces["laoo"].Insert(0, "Leelawadee UI"); map["laoo"].Insert(0, "Leelawadee UI");
MapScriptToTypefaces["thai"].Insert(0, "Leelawadee UI"); map["thai"].Insert(0, "Leelawadee UI");
MapScriptToTypefaces["zsye"].Insert(0, "Segoe UI Emoji"); map["zsye"].Insert(0, "Segoe UI Emoji");
} }
if (ver >= new Version(10, 0)) { // Windows 10 if (ver >= new Version(10, 0)) { // Windows 10
MapScriptToTypefaces["brah"].Insert(0, "Segoe UI Historic"); map["brah"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["cari"].Insert(0, "Segoe UI Historic"); map["cari"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["cprt"].Insert(0, "Segoe UI Historic"); map["cprt"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["egyp"].Insert(0, "Segoe UI Historic"); map["egyp"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["armi"].Insert(0, "Segoe UI Historic"); map["armi"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["phli"].Insert(0, "Segoe UI Historic"); map["phli"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["prti"].Insert(0, "Segoe UI Historic"); map["prti"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["khar"].Insert(0, "Segoe UI Historic"); map["khar"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["lyci"].Insert(0, "Segoe UI Historic"); map["lyci"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["lydi"].Insert(0, "Segoe UI Historic"); map["lydi"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["phnx"].Insert(0, "Segoe UI Historic"); map["phnx"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["xpeo"].Insert(0, "Segoe UI Historic"); map["xpeo"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["sarb"].Insert(0, "Segoe UI Historic"); map["sarb"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["shaw"].Insert(0, "Segoe UI Historic"); map["shaw"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["xsux"].Insert(0, "Segoe UI Historic"); map["xsux"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["ugar"].Insert(0, "Segoe UI Historic"); map["ugar"].Insert(0, "Segoe UI Historic");
// Segoe UI Symbol -> Segoe UI Historic // Segoe UI Symbol -> Segoe UI Historic
MapScriptToTypefaces["glag"].Insert(0, "Segoe UI Historic"); map["glag"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["goth"].Insert(0, "Segoe UI Historic"); map["goth"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["merc"].Insert(0, "Segoe UI Historic"); map["merc"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["ogam"].Insert(0, "Segoe UI Historic"); map["ogam"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["ital"].Insert(0, "Segoe UI Historic"); map["ital"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["orkh"].Insert(0, "Segoe UI Historic"); map["orkh"].Insert(0, "Segoe UI Historic");
MapScriptToTypefaces["runr"].Insert(0, "Segoe UI Historic"); map["runr"].Insert(0, "Segoe UI Historic");
// //
MapScriptToTypefaces["jpan"].Insert(0, "Yu Gothic UI"); map["jpan"].Insert(0, "Yu Gothic UI");
MapScriptToTypefaces["zsym"].Add("Segoe MDL2 Assets"); map["zsym"].Add("Segoe MDL2 Assets");
} }
return map;
} }
public void LoadDefaultAndroidFallbackList() { public static Dictionary<string, List<string>> GetDefaultAndroidFallbackMap() {
if (Environment.OSVersion.Platform != PlatformID.Unix) return; var map = new Dictionary<string, List<string>>();
MapScriptToTypefaces.Clear(); ScriptUtils.FillKeysWithScripts(map, () => new List<string>());
ScriptUtils.FillKeysWithScripts(MapScriptToTypefaces, () => new List<string>()); map["zyyy"].Insert(0, "Noto Sans CJK TC"); // TODO Modify default fallback
MapScriptToTypefaces["zyyy"].Insert(0, "Noto Sans CJK TC"); // TODO Modify default fallback map["zyyy"].Insert(0, "Noto Sans CJK JP");
MapScriptToTypefaces["zyyy"].Insert(0, "Noto Sans CJK JP"); map["zyyy"].Insert(0, "Noto Sans CJK SC");
MapScriptToTypefaces["zyyy"].Insert(0, "Noto Sans CJK SC"); map["zyyy"].Insert(0, "Roboto");
MapScriptToTypefaces["zyyy"].Insert(0, "Roboto"); map["zsye"].Insert(0, "Noto Color Emoji");
MapScriptToTypefaces["zsye"].Insert(0, "Noto Color Emoji"); map["zsye"].Add("Noto Color Emoji Flags");
MapScriptToTypefaces["zsye"].Add("Noto Color Emoji Flags"); map["arab"].Insert(0, "Noto Naskh Arabic");
MapScriptToTypefaces["arab"].Insert(0, "Noto Naskh Arabic"); map["adlm"].Insert(0, "Noto Sans Adlam");
MapScriptToTypefaces["adlm"].Insert(0, "Noto Sans Adlam"); map["ahom"].Insert(0, "Noto Sans Ahom");
MapScriptToTypefaces["ahom"].Insert(0, "Noto Sans Ahom"); map["hluw"].Insert(0, "Noto Sans Anatolian Hieroglyphs");
MapScriptToTypefaces["hluw"].Insert(0, "Noto Sans Anatolian Hieroglyphs"); map["armn"].Insert(0, "Noto Sans Armenian");
MapScriptToTypefaces["armn"].Insert(0, "Noto Sans Armenian"); map["avst"].Insert(0, "Noto Sans Avestan");
MapScriptToTypefaces["avst"].Insert(0, "Noto Sans Avestan"); map["bali"].Insert(0, "Noto Sans Balinese");
MapScriptToTypefaces["bali"].Insert(0, "Noto Sans Balinese"); map["bamu"].Insert(0, "Noto Sans Bamum");
MapScriptToTypefaces["bamu"].Insert(0, "Noto Sans Bamum"); map["bass"].Insert(0, "Noto Sans Bassa Vah");
MapScriptToTypefaces["bass"].Insert(0, "Noto Sans Bassa Vah"); map["batk"].Insert(0, "Noto Sans Batak");
MapScriptToTypefaces["batk"].Insert(0, "Noto Sans Batak"); map["beng"].Insert(0, "Noto Sans Bengali");
MapScriptToTypefaces["beng"].Insert(0, "Noto Sans Bengali"); map["bhks"].Insert(0, "Noto Sans Bhaiksuki");
MapScriptToTypefaces["bhks"].Insert(0, "Noto Sans Bhaiksuki"); map["brah"].Insert(0, "Noto Sans Brahmi");
MapScriptToTypefaces["brah"].Insert(0, "Noto Sans Brahmi"); map["bugi"].Insert(0, "Noto Sans Buginese");
MapScriptToTypefaces["bugi"].Insert(0, "Noto Sans Buginese"); map["buhd"].Insert(0, "Noto Sans Buhid");
MapScriptToTypefaces["buhd"].Insert(0, "Noto Sans Buhid"); map["jpan"].Insert(0, "Noto Sans CJK JP");
MapScriptToTypefaces["jpan"].Insert(0, "Noto Sans CJK JP"); map["kore"].Insert(0, "Noto Sans CJK KR");
MapScriptToTypefaces["kore"].Insert(0, "Noto Sans CJK KR"); map["hans"].Insert(0, "Noto Sans CJK SC");
MapScriptToTypefaces["hans"].Insert(0, "Noto Sans CJK SC"); map["hant"].Insert(0, "Noto Sans CJK TC");
MapScriptToTypefaces["hant"].Insert(0, "Noto Sans CJK TC"); map["hant"].Add("Noto Sans CJK HK");
MapScriptToTypefaces["hant"].Add("Noto Sans CJK HK"); map["cans"].Insert(0, "Noto Sans Canadian Aboriginal");
MapScriptToTypefaces["cans"].Insert(0, "Noto Sans Canadian Aboriginal"); map["cari"].Insert(0, "Noto Sans Carian");
MapScriptToTypefaces["cari"].Insert(0, "Noto Sans Carian"); map["cakm"].Insert(0, "Noto Sans Chakma");
MapScriptToTypefaces["cakm"].Insert(0, "Noto Sans Chakma"); map["cham"].Insert(0, "Noto Sans Cham");
MapScriptToTypefaces["cham"].Insert(0, "Noto Sans Cham"); map["cher"].Insert(0, "Noto Sans Cherokee");
MapScriptToTypefaces["cher"].Insert(0, "Noto Sans Cherokee"); map["copt"].Insert(0, "Noto Sans Coptic");
MapScriptToTypefaces["copt"].Insert(0, "Noto Sans Coptic"); map["xsux"].Insert(0, "Noto Sans Cuneiform");
MapScriptToTypefaces["xsux"].Insert(0, "Noto Sans Cuneiform"); map["cprt"].Insert(0, "Noto Sans Cypriot");
MapScriptToTypefaces["cprt"].Insert(0, "Noto Sans Cypriot"); map["dsrt"].Insert(0, "Noto Sans Deseret");
MapScriptToTypefaces["dsrt"].Insert(0, "Noto Sans Deseret"); map["deva"].Insert(0, "Noto Sans Devanagari");
MapScriptToTypefaces["deva"].Insert(0, "Noto Sans Devanagari"); map["egyp"].Insert(0, "Noto Sans Egyptian Hieroglyphs");
MapScriptToTypefaces["egyp"].Insert(0, "Noto Sans Egyptian Hieroglyphs"); map["elba"].Insert(0, "Noto Sans Elbasan");
MapScriptToTypefaces["elba"].Insert(0, "Noto Sans Elbasan"); map["ethi"].Insert(0, "Noto Sans Ethiopic");
MapScriptToTypefaces["ethi"].Insert(0, "Noto Sans Ethiopic"); map["geor"].Insert(0, "Noto Sans Georgian");
MapScriptToTypefaces["geor"].Insert(0, "Noto Sans Georgian"); map["glag"].Insert(0, "Noto Sans Glagolitic");
MapScriptToTypefaces["glag"].Insert(0, "Noto Sans Glagolitic"); map["goth"].Insert(0, "Noto Sans Gothic");
MapScriptToTypefaces["goth"].Insert(0, "Noto Sans Gothic"); map["gran"].Insert(0, "Noto Sans Grantha");
MapScriptToTypefaces["gran"].Insert(0, "Noto Sans Grantha"); map["gujr"].Insert(0, "Noto Sans Gujarati");
MapScriptToTypefaces["gujr"].Insert(0, "Noto Sans Gujarati"); map["gong"].Insert(0, "Noto Sans Gunjala Gondi");
MapScriptToTypefaces["gong"].Insert(0, "Noto Sans Gunjala Gondi"); map["guru"].Insert(0, "Noto Sans Gurmukhi");
MapScriptToTypefaces["guru"].Insert(0, "Noto Sans Gurmukhi"); map["rohg"].Insert(0, "Noto Sans Hanifi Rohingya");
MapScriptToTypefaces["rohg"].Insert(0, "Noto Sans Hanifi Rohingya"); map["hano"].Insert(0, "Noto Sans Hanunoo");
MapScriptToTypefaces["hano"].Insert(0, "Noto Sans Hanunoo"); map["hatr"].Insert(0, "Noto Sans Hatran");
MapScriptToTypefaces["hatr"].Insert(0, "Noto Sans Hatran"); map["hebr"].Insert(0, "Noto Sans Hebrew");
MapScriptToTypefaces["hebr"].Insert(0, "Noto Sans Hebrew"); map["armi"].Insert(0, "Noto Sans Imperial Aramaic");
MapScriptToTypefaces["armi"].Insert(0, "Noto Sans Imperial Aramaic"); map["phli"].Insert(0, "Noto Sans Inscriptional Pahlavi");
MapScriptToTypefaces["phli"].Insert(0, "Noto Sans Inscriptional Pahlavi"); map["prti"].Insert(0, "Noto Sans Inscriptional Parthian");
MapScriptToTypefaces["prti"].Insert(0, "Noto Sans Inscriptional Parthian"); map["java"].Insert(0, "Noto Sans Javanese");
MapScriptToTypefaces["java"].Insert(0, "Noto Sans Javanese"); map["kthi"].Insert(0, "Noto Sans Kaithi");
MapScriptToTypefaces["kthi"].Insert(0, "Noto Sans Kaithi"); map["knda"].Insert(0, "Noto Sans Kannada");
MapScriptToTypefaces["knda"].Insert(0, "Noto Sans Kannada"); map["kali"].Insert(0, "Noto Sans KayahLi");
MapScriptToTypefaces["kali"].Insert(0, "Noto Sans KayahLi"); map["khar"].Insert(0, "Noto Sans Kharoshthi");
MapScriptToTypefaces["khar"].Insert(0, "Noto Sans Kharoshthi"); map["khmr"].Insert(0, "Noto Sans Khmer");
MapScriptToTypefaces["khmr"].Insert(0, "Noto Sans Khmer"); map["khoj"].Insert(0, "Noto Sans Khojki");
MapScriptToTypefaces["khoj"].Insert(0, "Noto Sans Khojki"); map["laoo"].Insert(0, "Noto Sans Lao");
MapScriptToTypefaces["laoo"].Insert(0, "Noto Sans Lao"); map["lepc"].Insert(0, "Noto Sans Lepcha");
MapScriptToTypefaces["lepc"].Insert(0, "Noto Sans Lepcha"); map["limb"].Insert(0, "Noto Sans Limbu");
MapScriptToTypefaces["limb"].Insert(0, "Noto Sans Limbu"); map["lina"].Insert(0, "Noto Sans Linear A");
MapScriptToTypefaces["lina"].Insert(0, "Noto Sans Linear A"); map["linb"].Insert(0, "Noto Sans Linear B");
MapScriptToTypefaces["linb"].Insert(0, "Noto Sans Linear B"); map["lisu"].Insert(0, "Noto Sans Lisu");
MapScriptToTypefaces["lisu"].Insert(0, "Noto Sans Lisu"); map["lyci"].Insert(0, "Noto Sans Lycian");
MapScriptToTypefaces["lyci"].Insert(0, "Noto Sans Lycian"); map["lydi"].Insert(0, "Noto Sans Lydian");
MapScriptToTypefaces["lydi"].Insert(0, "Noto Sans Lydian"); map["mlym"].Insert(0, "Noto Sans Malayalam");
MapScriptToTypefaces["mlym"].Insert(0, "Noto Sans Malayalam"); map["mand"].Insert(0, "Noto Sans Mandiac");
MapScriptToTypefaces["mand"].Insert(0, "Noto Sans Mandiac"); map["mani"].Insert(0, "Noto Sans Manichaean");
MapScriptToTypefaces["mani"].Insert(0, "Noto Sans Manichaean"); map["marc"].Insert(0, "Noto Sans Marchen");
MapScriptToTypefaces["marc"].Insert(0, "Noto Sans Marchen"); map["gonm"].Insert(0, "Noto Sans Masaram Gondi");
MapScriptToTypefaces["gonm"].Insert(0, "Noto Sans Masaram Gondi"); map["medf"].Insert(0, "Noto Sans Medefaidrin");
MapScriptToTypefaces["medf"].Insert(0, "Noto Sans Medefaidrin"); map["mtei"].Insert(0, "Noto Sans Meetei Mayek");
MapScriptToTypefaces["mtei"].Insert(0, "Noto Sans Meetei Mayek"); map["merc"].Insert(0, "Noto Sans Meroitic");
MapScriptToTypefaces["merc"].Insert(0, "Noto Sans Meroitic"); map["mero"].Insert(0, "Noto Sans Meroitic");
MapScriptToTypefaces["mero"].Insert(0, "Noto Sans Meroitic"); map["plrd"].Insert(0, "Noto Sans Miao");
MapScriptToTypefaces["plrd"].Insert(0, "Noto Sans Miao"); map["modi"].Insert(0, "Noto Sans Modi");
MapScriptToTypefaces["modi"].Insert(0, "Noto Sans Modi"); map["mong"].Insert(0, "Noto Sans Mongolian");
MapScriptToTypefaces["mong"].Insert(0, "Noto Sans Mongolian"); map["mroo"].Insert(0, "Noto Sans Mro");
MapScriptToTypefaces["mroo"].Insert(0, "Noto Sans Mro"); map["mult"].Insert(0, "Noto Sans Multani");
MapScriptToTypefaces["mult"].Insert(0, "Noto Sans Multani"); map["mymr"].Insert(0, "Noto Sans Myanmar");
MapScriptToTypefaces["mymr"].Insert(0, "Noto Sans Myanmar"); map["nkoo"].Insert(0, "Noto Sans Nko");
MapScriptToTypefaces["nkoo"].Insert(0, "Noto Sans Nko"); map["nbat"].Insert(0, "Noto Sans Nabataean");
MapScriptToTypefaces["nbat"].Insert(0, "Noto Sans Nabataean"); map["talu"].Insert(0, "Noto Sans New Tai Lue");
MapScriptToTypefaces["talu"].Insert(0, "Noto Sans New Tai Lue"); map["newa"].Insert(0, "Noto Sans Newa");
MapScriptToTypefaces["newa"].Insert(0, "Noto Sans Newa"); map["ogam"].Insert(0, "Noto Sans Ogham");
MapScriptToTypefaces["ogam"].Insert(0, "Noto Sans Ogham"); map["olck"].Insert(0, "Noto Sans Ol Chiki");
MapScriptToTypefaces["olck"].Insert(0, "Noto Sans Ol Chiki"); map["ital"].Insert(0, "Noto Sans Old Italian");
MapScriptToTypefaces["ital"].Insert(0, "Noto Sans Old Italian"); map["narb"].Insert(0, "Noto Sans Old North Arabian");
MapScriptToTypefaces["narb"].Insert(0, "Noto Sans Old North Arabian"); map["perm"].Insert(0, "Noto Sans Old Permic");
MapScriptToTypefaces["perm"].Insert(0, "Noto Sans Old Permic"); map["xpeo"].Insert(0, "Noto Sans Old Persian");
MapScriptToTypefaces["xpeo"].Insert(0, "Noto Sans Old Persian"); map["sarb"].Insert(0, "Noto Sans Old South Arabian");
MapScriptToTypefaces["sarb"].Insert(0, "Noto Sans Old South Arabian"); map["orkh"].Insert(0, "Noto Sans Old Turkic");
MapScriptToTypefaces["orkh"].Insert(0, "Noto Sans Old Turkic"); map["orya"].Insert(0, "Noto Sans Oriya");
MapScriptToTypefaces["orya"].Insert(0, "Noto Sans Oriya"); map["osge"].Insert(0, "Noto Sans Osage");
MapScriptToTypefaces["osge"].Insert(0, "Noto Sans Osage"); map["osma"].Insert(0, "Noto Sans Osmanya");
MapScriptToTypefaces["osma"].Insert(0, "Noto Sans Osmanya"); map["hmng"].Insert(0, "Noto Sans Pahawh Hmong");
MapScriptToTypefaces["hmng"].Insert(0, "Noto Sans Pahawh Hmong"); map["palm"].Insert(0, "Noto Sans Palmyrene");
MapScriptToTypefaces["palm"].Insert(0, "Noto Sans Palmyrene"); map["pauc"].Insert(0, "Noto Sans Pau Cin Hau");
MapScriptToTypefaces["pauc"].Insert(0, "Noto Sans Pau Cin Hau"); map["phag"].Insert(0, "Noto Sans Phags Pa");
MapScriptToTypefaces["phag"].Insert(0, "Noto Sans Phags Pa"); map["phnx"].Insert(0, "Noto Sans Phoenician");
MapScriptToTypefaces["phnx"].Insert(0, "Noto Sans Phoenician"); map["rjng"].Insert(0, "Noto Sans Rejang");
MapScriptToTypefaces["rjng"].Insert(0, "Noto Sans Rejang"); map["runr"].Insert(0, "Noto Sans Runic");
MapScriptToTypefaces["runr"].Insert(0, "Noto Sans Runic"); map["samr"].Insert(0, "Noto Sans Samaritan");
MapScriptToTypefaces["samr"].Insert(0, "Noto Sans Samaritan"); map["saur"].Insert(0, "Noto Sans Saurashtra");
MapScriptToTypefaces["saur"].Insert(0, "Noto Sans Saurashtra"); map["shrd"].Insert(0, "Noto Sans Sharada");
MapScriptToTypefaces["shrd"].Insert(0, "Noto Sans Sharada"); map["shaw"].Insert(0, "Noto Sans Shavian");
MapScriptToTypefaces["shaw"].Insert(0, "Noto Sans Shavian"); map["sinh"].Insert(0, "Noto Sans Sinhala");
MapScriptToTypefaces["sinh"].Insert(0, "Noto Sans Sinhala"); map["sora"].Insert(0, "Noto Sans Sora Sompeng");
MapScriptToTypefaces["sora"].Insert(0, "Noto Sans Sora Sompeng"); map["soyo"].Insert(0, "Noto Sans Soyombo");
MapScriptToTypefaces["soyo"].Insert(0, "Noto Sans Soyombo"); map["sund"].Insert(0, "Noto Sans Sundanese");
MapScriptToTypefaces["sund"].Insert(0, "Noto Sans Sundanese"); map["sylo"].Insert(0, "Noto Sans Syloti Nagri");
MapScriptToTypefaces["sylo"].Insert(0, "Noto Sans Syloti Nagri"); map["zsym"].Insert(0, "Noto Sans Symbols");
MapScriptToTypefaces["zsym"].Insert(0, "Noto Sans Symbols"); map["syrn"].Insert(0, "Noto Sans Syriac Eastern");
MapScriptToTypefaces["syrn"].Insert(0, "Noto Sans Syriac Eastern"); map["syre"].Insert(0, "Noto Sans Syriac Estrangela");
MapScriptToTypefaces["syre"].Insert(0, "Noto Sans Syriac Estrangela"); map["syrj"].Insert(0, "Noto Sans Syriac Western");
MapScriptToTypefaces["syrj"].Insert(0, "Noto Sans Syriac Western"); map["tglg"].Insert(0, "Noto Sans Tagalog");
MapScriptToTypefaces["tglg"].Insert(0, "Noto Sans Tagalog"); map["tagb"].Insert(0, "Noto Sans Tagbanwa");
MapScriptToTypefaces["tagb"].Insert(0, "Noto Sans Tagbanwa"); map["tale"].Insert(0, "Noto Sans Tai Le");
MapScriptToTypefaces["tale"].Insert(0, "Noto Sans Tai Le"); map["lana"].Insert(0, "Noto Sans Tai Tham");
MapScriptToTypefaces["lana"].Insert(0, "Noto Sans Tai Tham"); map["tavt"].Insert(0, "Noto Sans Tai Viet");
MapScriptToTypefaces["tavt"].Insert(0, "Noto Sans Tai Viet"); map["takr"].Insert(0, "Noto Sans Takri");
MapScriptToTypefaces["takr"].Insert(0, "Noto Sans Takri"); map["taml"].Insert(0, "Noto Sans Tamil");
MapScriptToTypefaces["taml"].Insert(0, "Noto Sans Tamil"); map["telu"].Insert(0, "Noto Sans Telugu");
MapScriptToTypefaces["telu"].Insert(0, "Noto Sans Telugu"); map["thaa"].Insert(0, "Noto Sans Thaana");
MapScriptToTypefaces["thaa"].Insert(0, "Noto Sans Thaana"); map["thai"].Insert(0, "Noto Sans Thai");
MapScriptToTypefaces["thai"].Insert(0, "Noto Sans Thai"); map["tfng"].Insert(0, "Noto Sans Tifinagh");
MapScriptToTypefaces["tfng"].Insert(0, "Noto Sans Tifinagh"); map["ugar"].Insert(0, "Noto Sans Ugaritic");
MapScriptToTypefaces["ugar"].Insert(0, "Noto Sans Ugaritic"); map["vaii"].Insert(0, "Noto Sans Vai");
MapScriptToTypefaces["vaii"].Insert(0, "Noto Sans Vai"); map["wcho"].Insert(0, "Noto Sans Wancho");
MapScriptToTypefaces["wcho"].Insert(0, "Noto Sans Wancho"); map["wara"].Insert(0, "Noto Sans Warang Citi");
MapScriptToTypefaces["wara"].Insert(0, "Noto Sans Warang Citi"); map["yiii"].Insert(0, "Noto Sans Yi");
MapScriptToTypefaces["yiii"].Insert(0, "Noto Sans Yi"); return map;
} }
public FallbackListFontMatcher(FontManager manager) : base(manager) { } public FallbackListFontMatcher(FontManager manager) : base(manager) { }
public override IEnumerable<Typeface> MatchScript(string script = null, bool distinctFamily = false) { public override IEnumerable<Typeface> MatchScript(string script = null, bool distinctFamily = false) {

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
#pragma warning disable IDE0049
namespace Cryville.Common.Font { namespace Cryville.Common.Font {
public abstract class FontTable<T> { public abstract class FontTable<T> {
protected UInt32 Offset { get; private set; } protected UInt32 Offset { get; private set; }
@@ -25,14 +26,17 @@ namespace Cryville.Common.Font {
readonly UInt16 minorVersion; readonly UInt16 minorVersion;
readonly UInt32 numFonts; readonly UInt32 numFonts;
readonly List<UInt32> tableDirectoryOffsets = new List<UInt32>(); readonly List<UInt32> tableDirectoryOffsets = new List<UInt32>();
#pragma warning disable IDE0052 // Reserved
readonly String dsigTag; readonly String dsigTag;
readonly UInt32 dsigLength; readonly UInt32 dsigLength;
readonly UInt32 dsigOffset; readonly UInt32 dsigOffset;
#pragma warning restore IDE0052 // Reserved
public TTCHeader(BinaryReader reader, UInt32 offset) : base(reader, offset) { public TTCHeader(BinaryReader reader, UInt32 offset) : base(reader, offset) {
ttcTag = reader.ReadTag(); ttcTag = reader.ReadTag();
if (ttcTag != "ttcf") throw new NotImplementedException(); if (ttcTag != "ttcf") throw new NotSupportedException();
majorVersion = reader.ReadUInt16(); majorVersion = reader.ReadUInt16();
minorVersion = reader.ReadUInt16(); minorVersion = reader.ReadUInt16();
if (minorVersion != 0) throw new NotSupportedException();
numFonts = reader.ReadUInt32(); numFonts = reader.ReadUInt32();
for (UInt32 i = 0; i < numFonts; i++) tableDirectoryOffsets.Add(reader.ReadUInt32()); for (UInt32 i = 0; i < numFonts; i++) tableDirectoryOffsets.Add(reader.ReadUInt32());
if (majorVersion == 2) { if (majorVersion == 2) {
@@ -52,12 +56,16 @@ namespace Cryville.Common.Font {
public sealed class TableDirectory : FontTable<TableRecord, object> { public sealed class TableDirectory : FontTable<TableRecord, object> {
readonly UInt32 sfntVersion; readonly UInt32 sfntVersion;
readonly UInt16 numTables; readonly UInt16 numTables;
#pragma warning disable IDE0052 // Reserved
readonly UInt16 searchRange; readonly UInt16 searchRange;
readonly UInt16 entrySelector; readonly UInt16 entrySelector;
readonly UInt16 rangeShift; readonly UInt16 rangeShift;
#pragma warning restore IDE0052 // Reserved
readonly List<TableRecord> tableRecords = new List<TableRecord>(); readonly List<TableRecord> tableRecords = new List<TableRecord>();
public TableDirectory(BinaryReader reader, UInt32 offset) : base(reader, offset) { public TableDirectory(BinaryReader reader, UInt32 offset) : base(reader, offset) {
sfntVersion = reader.ReadUInt32(); sfntVersion = reader.ReadUInt32();
if (sfntVersion != 0x00010000 && sfntVersion != 0x4F54544F &&
sfntVersion != 0x74727565 && sfntVersion != 0x74797031) throw new NotSupportedException();
numTables = reader.ReadUInt16(); numTables = reader.ReadUInt16();
searchRange = reader.ReadUInt16(); searchRange = reader.ReadUInt16();
entrySelector = reader.ReadUInt16(); entrySelector = reader.ReadUInt16();
@@ -99,48 +107,63 @@ namespace Cryville.Common.Font {
count = reader.ReadUInt16(); count = reader.ReadUInt16();
storageOffset = reader.ReadUInt16(); storageOffset = reader.ReadUInt16();
for (UInt16 i = 0; i < count; i++) for (UInt16 i = 0; i < count; i++)
nameRecord.Add(new NameRecord { nameRecord.Add(new NameRecord(
platformID = reader.ReadUInt16(), reader.ReadUInt16(),
encodingID = reader.ReadUInt16(), reader.ReadUInt16(),
languageID = reader.ReadUInt16(), reader.ReadUInt16(),
nameID = (NameID)reader.ReadUInt16(), (NameID)reader.ReadUInt16(),
length = reader.ReadUInt16(), reader.ReadUInt16(),
stringOffset = reader.ReadUInt16(), reader.ReadUInt16()
}); ));
if (version == 1) { if (version == 1) {
langTagCount = reader.ReadUInt16(); langTagCount = reader.ReadUInt16();
for (UInt16 i = 0; i < langTagCount; i++) for (UInt16 i = 0; i < langTagCount; i++)
langTagRecord.Add(new LangTagRecord { langTagRecord.Add(new LangTagRecord(
length = reader.ReadUInt16(), reader.ReadUInt16(),
langTagOffset = reader.ReadUInt16(), reader.ReadUInt16()
}); ));
}
foreach (var i in nameRecord)
i.Load(reader, offset + storageOffset);
if (version == 1) {
foreach (var i in langTagRecord)
i.Load(reader, offset + storageOffset);
} }
UInt32 origin = (UInt32)reader.BaseStream.Position;
for (int i = 0; i < nameRecord.Count; i++) nameRecord[i] = nameRecord[i].Load(reader, origin);
for (int i = 0; i < langTagRecord.Count; i++) langTagRecord[i] = langTagRecord[i].Load(reader, origin);
} }
public sealed override IReadOnlyList<NameRecord> GetItems() { public sealed override IReadOnlyList<NameRecord> GetItems() {
return nameRecord; return nameRecord;
} }
} }
public struct NameRecord { public class NameRecord {
public UInt16 platformID; public UInt16 PlatformID { get; private set; }
public UInt16 encodingID; public UInt16 EncodingID { get; private set; }
public UInt16 languageID; public UInt16 LanguageID { get; private set; }
public NameID nameID; public NameID NameID { get; private set; }
public UInt16 length; public UInt16 Length { get; private set; }
public UInt16 stringOffset; public UInt16 StringOffset { get; private set; }
public String value { get; private set; } public String Value { get; private set; }
public NameRecord Load(BinaryReader reader, UInt32 origin) { public NameRecord(UInt16 platformID, UInt16 encodingID, UInt16 languageID, NameID nameID, UInt16 length, UInt16 stringOffset) {
reader.BaseStream.Position = origin + stringOffset; PlatformID = platformID;
Encoding encoding; EncodingID = encodingID;
switch (platformID) { LanguageID = languageID;
case 0: encoding = Encoding.BigEndianUnicode; break; NameID = nameID;
case 3: encoding = Encoding.BigEndianUnicode; break; Length = length;
default: return this; StringOffset = stringOffset;
} }
value = encoding.GetString(reader.ReadBytes(length)); public void Load(BinaryReader reader, UInt32 origin) {
return this; reader.BaseStream.Position = origin + StringOffset;
Encoding encoding;
try {
switch (PlatformID) {
case 0: encoding = Encoding.BigEndianUnicode; break;
case 1: encoding = Encoding.GetEncoding(10000 + EncodingID); break;
case 3: encoding = Encoding.BigEndianUnicode; break;
default: return;
}
}
catch (NotSupportedException) { return; }
catch (ArgumentException) { return; }
Value = encoding.GetString(reader.ReadBytes(Length));
} }
} }
public enum NameID : UInt16 { public enum NameID : UInt16 {
@@ -171,47 +194,58 @@ namespace Cryville.Common.Font {
DarkBackgroundPalette = 24, DarkBackgroundPalette = 24,
VariationsPostScriptNamePrefix = 25, VariationsPostScriptNamePrefix = 25,
} }
public struct LangTagRecord { public class LangTagRecord {
public UInt16 length; public UInt16 Length { get; private set; }
public UInt16 langTagOffset; public UInt16 LangTagOffset { get; private set; }
public String value { get; private set; } public String Value { get; private set; }
public LangTagRecord Load(BinaryReader reader, UInt32 origin) { public LangTagRecord(UInt16 length, UInt16 langTagOffset) {
reader.BaseStream.Position = origin + langTagOffset; Length = length;
value = Encoding.BigEndianUnicode.GetString(reader.ReadBytes(length)); LangTagOffset = langTagOffset;
return this; }
public void Load(BinaryReader reader, UInt32 origin) {
reader.BaseStream.Position = origin + LangTagOffset;
Value = Encoding.BigEndianUnicode.GetString(reader.ReadBytes(Length));
} }
} }
public sealed class MetaTable : FontTable<DataMap> { public sealed class MetaTable : FontTable<DataMap> {
readonly UInt32 version; readonly UInt32 version;
#pragma warning disable IDE0052 // Reserved
readonly UInt32 flags; readonly UInt32 flags;
#pragma warning restore IDE0052 // Reserved
readonly UInt32 dataMapCount; readonly UInt32 dataMapCount;
readonly List<DataMap> dataMaps = new List<DataMap>(); readonly List<DataMap> dataMaps = new List<DataMap>();
public MetaTable(BinaryReader reader, UInt32 offset) : base(reader, offset) { public MetaTable(BinaryReader reader, UInt32 offset) : base(reader, offset) {
version = reader.ReadUInt32(); version = reader.ReadUInt32();
if (version != 1) throw new NotSupportedException();
flags = reader.ReadUInt32(); flags = reader.ReadUInt32();
reader.ReadUInt32(); reader.ReadUInt32();
dataMapCount = reader.ReadUInt32(); dataMapCount = reader.ReadUInt32();
for (UInt32 i = 0; i < dataMapCount; i++) for (UInt32 i = 0; i < dataMapCount; i++)
dataMaps.Add(new DataMap { dataMaps.Add(new DataMap (
tag = reader.ReadTag(), reader.ReadTag(),
dataOffset = reader.ReadUInt32(), reader.ReadUInt32(),
dataLength = reader.ReadUInt32(), reader.ReadUInt32()
}); ));
for (int i = 0; i < dataMaps.Count; i++) dataMaps[i] = dataMaps[i].Load(reader, offset); foreach (var i in dataMaps)
i.Load(reader, offset);
} }
public sealed override IReadOnlyList<DataMap> GetItems() { public sealed override IReadOnlyList<DataMap> GetItems() {
return dataMaps; return dataMaps;
} }
} }
public struct DataMap { public class DataMap {
public String tag; public String Tag { get; private set; }
public UInt32 dataOffset; public UInt32 DataOffset { get; private set; }
public UInt32 dataLength; public UInt32 DataLength { get; private set; }
public String value { get; private set; } public String Value { get; private set; }
public DataMap Load(BinaryReader reader, UInt32 origin) { public DataMap(String tag, UInt32 dataOffset, UInt32 dataLength) {
reader.BaseStream.Position = origin + dataOffset; Tag = tag;
value = Encoding.ASCII.GetString(reader.ReadBytes((int)dataLength)); DataOffset = dataOffset;
return this; DataLength = dataLength;
}
public void Load(BinaryReader reader, UInt32 origin) {
reader.BaseStream.Position = origin + DataOffset;
Value = Encoding.ASCII.GetString(reader.ReadBytes((int)DataLength));
} }
} }
public static class BinaryReaderExtensions { public static class BinaryReaderExtensions {

View File

@@ -23,9 +23,9 @@ namespace Cryville.Common.Font {
protected override void GetName(BinaryReader reader) { protected override void GetName(BinaryReader reader) {
var dir = new TableDirectory(reader, (uint)reader.BaseStream.Position); var dir = new TableDirectory(reader, (uint)reader.BaseStream.Position);
var nameTable = (NameTable)dir.GetSubTable((from i in dir.GetItems() where i.tableTag == "name" select i).Single()); var nameTable = (NameTable)dir.GetSubTable((from i in dir.GetItems() where i.tableTag == "name" select i).Single());
FamilyName = (from i in nameTable.GetItems() where i.nameID == NameID.FontFamilyName && i.value != null select i.value).First(); FamilyName = (from i in nameTable.GetItems() where i.NameID == NameID.FontFamilyName && i.Value != null select i.Value).First();
SubfamilyName = (from i in nameTable.GetItems() where i.nameID == NameID.FontSubfamilyName && i.value != null select i.value).First(); SubfamilyName = (from i in nameTable.GetItems() where i.NameID == NameID.FontSubfamilyName && i.Value != null select i.Value).First();
FullName = (from i in nameTable.GetItems() where i.nameID == NameID.FullFontName && i.value != null select i.value).First(); FullName = (from i in nameTable.GetItems() where i.NameID == NameID.FullFontName && i.Value != null select i.Value).First();
} }
} }
} }

View File

@@ -4,12 +4,12 @@ namespace Cryville.Common {
public struct Identifier : IEquatable<Identifier> { public struct Identifier : IEquatable<Identifier> {
public static Identifier Empty = new Identifier(0); public static Identifier Empty = new Identifier(0);
public int Key { get; private set; } public int Key { get; private set; }
public object Name { get { return IdentifierManager.SharedInstance.Retrieve(Key); } } public object Name { get { return IdentifierManager.Shared.Retrieve(Key); } }
public Identifier(int key) { public Identifier(int key) {
Key = key; Key = key;
} }
public Identifier(object name) { public Identifier(object name) {
Key = IdentifierManager.SharedInstance.Request(name); Key = IdentifierManager.Shared.Request(name);
} }
public override bool Equals(object obj) { public override bool Equals(object obj) {
if (obj == null || !(obj is Identifier)) return false; if (obj == null || !(obj is Identifier)) return false;

View File

@@ -1,52 +0,0 @@
using System.Collections.Generic;
namespace Cryville.Common {
/// <summary>
/// A manager that assigns each given identifiers a unique integer ID.
/// </summary>
public class IdentifierManager {
/// <summary>
/// A shared instance of the <see cref="IdentifierManager" /> class.
/// </summary>
public static IdentifierManager SharedInstance = new IdentifierManager();
readonly Dictionary<object, int> _idents = new Dictionary<object, int>();
readonly List<object> _ids = new List<object>();
readonly object _syncRoot = new object();
/// <summary>
/// Creates an instance of the <see cref="IdentifierManager" /> class.
/// </summary>
public IdentifierManager() {
Request(this);
}
/// <summary>
/// Requests an integer ID for an identifier.
/// </summary>
/// <param name="ident">The identifier.</param>
/// <returns>The integer ID.</returns>
public int Request(object ident) {
lock (_syncRoot) {
int id;
if (!_idents.TryGetValue(ident, out id)) {
_idents.Add(ident, id = _idents.Count);
_ids.Add(ident);
}
return id;
}
}
/// <summary>
/// Retrieves the identifier assigned with an integer ID.
/// </summary>
/// <param name="id">The integer ID.</param>
/// <returns>The identifier.</returns>
public object Retrieve(int id) {
lock (_syncRoot) {
return _ids[id];
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 478086496f56eaf46be4df4e2ad37fee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,128 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
namespace Cryville.Common {
/// <summary>
/// A logger.
/// </summary>
public abstract class Logger {
static readonly Dictionary<string, Logger> Instances = new Dictionary<string, Logger>();
static readonly Dictionary<string, StreamWriter> Files = new Dictionary<string, StreamWriter>();
static string logPath = null;
/// <summary>
/// Sets the path where the log files shall be stored.
/// </summary>
/// <param name="path">The path.</param>
public static void SetLogPath(string path) {
logPath = path;
var dir = new DirectoryInfo(path);
if (!dir.Exists) dir.Create();
}
/// <summary>
/// Logs to the specified logger.
/// </summary>
/// <param name="key">The key of the logger.</param>
/// <param name="level">The severity level.</param>
/// <param name="module">The module that is logging.</param>
/// <param name="format">The format string.</param>
/// <param name="args">The arguments for formatting.</param>
public static void Log(string key, int level, string module, string format, params object[] args) {
if (!Instances.ContainsKey(key)) return;
Instances[key].Log(level, module, string.Format(format, args));
if (Files.ContainsKey(key)) Files[key].WriteLine("[{0:O}] [{1}] <{2}> {3}", DateTime.UtcNow, level, module, string.Format(format, args));
}
/// <summary>
/// Adds a created logger to the shared logger manager.
/// </summary>
/// <param name="key">The key of the logger.</param>
/// <param name="logger">The logger.</param>
public static void Create(string key, Logger logger) {
Instances[key] = logger;
if (logPath != null) {
Files[key] = new StreamWriter(logPath + "/" + ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds).ToString(CultureInfo.InvariantCulture) + "-" + key + ".log") {
AutoFlush = true
};
}
}
/// <summary>
/// Closes all loggers and related file streams.
/// </summary>
public static void Close() {
Instances.Clear();
foreach (var f in Files) f.Value.Dispose();
Files.Clear();
}
/// <summary>
/// Logs to the logger.
/// </summary>
/// <param name="level">The severity level.</param>
/// <param name="module">The module that is logging.</param>
/// <param name="msg">The message.</param>
public virtual void Log(int level, string module, string msg) { }
}
/// <summary>
/// A <see cref="Logger" /> that calls a callback function on log.
/// </summary>
public class InstantLogger : Logger {
readonly Action<int, string, string> callback;
/// <summary>
/// Creates an instance of the <see cref="InstantLogger" /> class.
/// </summary>
/// <param name="callback">The callback function.</param>
/// <exception cref="ArgumentNullException"><paramref name="callback" /> is <see langword="null" />.</exception>
public InstantLogger(Action<int, string, string> callback) {
if (callback == null)
throw new ArgumentNullException("callback");
this.callback = callback;
}
/// <inheritdoc />
public override void Log(int level, string module, string msg) {
base.Log(level, module, msg);
callback(level, module, msg);
}
}
/// <summary>
/// A <see cref="Logger" /> that buffers the logs for enumeration.
/// </summary>
public class BufferedLogger : Logger {
readonly List<LogEntry> buffer = new List<LogEntry>();
/// <summary>
/// Creates an instance of the <see cref="BufferedLogger" /> class.
/// </summary>
public BufferedLogger() { }
/// <inheritdoc />
public override void Log(int level, string module, string msg) {
base.Log(level, module, msg);
lock (buffer) {
buffer.Add(new LogEntry(level, module, msg));
}
}
/// <summary>
/// Enumerates the buffered logs.
/// </summary>
/// <param name="callback">The callback function to receive the logs.</param>
public void Enumerate(Action<int, string, string> callback) {
lock (buffer) {
foreach (var i in buffer) {
callback(i.level, i.module, i.msg);
}
}
buffer.Clear();
}
}
struct LogEntry {
public int level;
public string module;
public string msg;
public LogEntry(int level, string module, string msg) {
this.level = level;
this.module = module;
this.msg = msg;
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 1c1729cfde78f1c479c9f7eb166e0107
timeCreated: 1611126212
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 53f4e3167a1eee2478b0abc6302aee8f guid: 1a624371d4108614b9cdc4acca1499e2
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@@ -1,14 +1,14 @@
using Cryville.Common.Logging;
using Microsoft.Win32; using Microsoft.Win32;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
namespace Cryville.Common.Network { namespace Cryville.Common.Network.Http11 {
public class HttpClient { public class Http11Client : IDisposable {
private readonly string _directHost; private readonly string _directHost;
protected string DirectHost { get { return _directHost; } } protected string DirectHost { get { return _directHost; } }
@@ -18,29 +18,17 @@ namespace Cryville.Common.Network {
readonly Uri _baseUri; readonly Uri _baseUri;
readonly int origPort; readonly int origPort;
protected string Version = "HTTP/1.1"; protected const string Version = "HTTP/1.1";
protected TcpClient TcpClient { get; private set; } protected TcpClient TcpClient { get; private set; }
protected Stream RawTcpStream { protected Stream RawTcpStream { get { return TcpClient.GetStream(); } }
get { protected virtual Stream Stream { get { return TcpClient.GetStream(); } }
return TcpClient.GetStream(); protected virtual string WindowsProxyProtocolName { get { return "http"; } }
}
}
protected virtual Stream Stream {
get {
return TcpClient.GetStream();
}
}
protected virtual string WindowsProxyProtocolName {
get {
return "http";
}
}
private readonly bool _proxied = false; private readonly bool _proxied = false;
public Dictionary<string, string> Headers { get; set; } public Dictionary<string, string> Headers { get; set; }
public HttpClient(Uri baseUri, int port = 80) { public Http11Client(Uri baseUri, int port = 80) {
_directHost = baseUri.Host; _directHost = baseUri.Host;
_directPort = port; _directPort = port;
_baseUri = baseUri; _baseUri = baseUri;
@@ -61,17 +49,28 @@ namespace Cryville.Common.Network {
TcpClient.Close(); TcpClient.Close();
} }
public HttpResponse Request(string method, Uri uri, string body = null, Encoding encoding = null) { public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposing) {
if (disposing) {
Close();
}
}
public Http11Response Request(string method, Uri uri, string body = null, Encoding encoding = null) {
string struri = GetUri(uri).PathAndQuery; string struri = GetUri(uri).PathAndQuery;
return Request(Stream, method, struri, body, encoding); return Request(Stream, method, struri, body, encoding);
} }
public HttpResponse Request(Stream stream, string method, string uri, string body = null, Encoding encoding = null) { Http11Response Request(Stream stream, string method, string uri, string body = null, Encoding encoding = null) {
var headers = new Dictionary<string, string>(); var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var h in Headers) foreach (var h in Headers)
headers.Add(h.Key, h.Value); headers.Add(h.Key, h.Value);
headers["Host"] = _baseUri.Host; headers["Host"] = _baseUri.Host;
byte[] payload = new byte[0]; byte[] payload = null;
if (body != null) { if (body != null) {
if (encoding == null) if (encoding == null)
encoding = Encoding.UTF8; encoding = Encoding.UTF8;
@@ -79,22 +78,24 @@ namespace Cryville.Common.Network {
headers.Add("Content-Encoding", encoding.EncodingName); headers.Add("Content-Encoding", encoding.EncodingName);
headers.Add("Content-Length", payload.Length.ToString(CultureInfo.InvariantCulture)); headers.Add("Content-Length", payload.Length.ToString(CultureInfo.InvariantCulture));
} }
string request_line = string.Format( using (var writer = new StreamWriter(stream, Encoding.ASCII, 1024, true)) {
"{0} {1} {2}\r\n", method, uri, Version writer.Write(method);
); writer.Write(' ');
string header_fields = string.Concat(( writer.Write(uri);
from h in headers select h.Key + ":" + h.Value + "\r\n" writer.Write(' ');
).ToArray()); writer.Write(Version);
byte[] buffer0 = Encoding.ASCII.GetBytes(string.Format( writer.Write("\r\n");
"{0}{1}\r\n", request_line, header_fields foreach (var header in headers) {
)); writer.Write(header.Key);
byte[] buffer1 = new byte[buffer0.Length + payload.Length]; writer.Write(':');
Array.Copy(buffer0, buffer1, buffer0.Length); writer.Write(header.Value);
Array.Copy(payload, 0, buffer1, buffer0.Length, payload.Length); writer.Write("\r\n");
Logger.Log("main", 0, "Network", Encoding.UTF8.GetString(buffer1)); }
stream.Write(buffer1, 0, buffer1.Length); writer.Write("\r\n");
stream.Flush(); if (payload != null) writer.Write(payload);
var response = new HttpResponse(stream); writer.Flush();
}
var response = new Http11Response(stream);
Logger.Log("main", 0, "Network", "{0}", response); Logger.Log("main", 0, "Network", "{0}", response);
return response; return response;
} }

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 2745c44c3cc32be4ab3a43888c14b9a1 guid: 5a795e416e54c69418de1a3c27a88932
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -1,30 +1,41 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace Cryville.Common.Network { namespace Cryville.Common.Network.Http11 {
public class HttpResponse { public class Http11Response : IDisposable {
static readonly char[] spchar = new char[]{ ' ' }; static readonly char[] spchar = new char[]{ ' ' };
public string HttpVersion { get; private set; } public string HttpVersion { get; private set; }
public string StatusCode { get; private set; } public string StatusCode { get; private set; }
public string ReasonPhase { get; private set; } public string ReasonPhase { get; private set; }
public Dictionary<string, string> Headers { get; private set; } public Dictionary<string, string> Headers { get; private set; }
public HttpResponseStream MessageBody { get; private set; } public Http11ResponseStream MessageBody { get; private set; }
internal HttpResponse(Stream stream) { internal Http11Response(Stream stream) {
var reader = new BinaryReader(stream, Encoding.ASCII); var reader = new BinaryReader(stream, Encoding.ASCII);
var statu_line = ReadLine(reader).Split(spchar, 3); var statu_line = ReadLine(reader).Split(spchar, 3);
HttpVersion = statu_line[0]; HttpVersion = statu_line[0];
StatusCode = statu_line[1]; StatusCode = statu_line[1];
ReasonPhase = statu_line[2]; ReasonPhase = statu_line[2];
Logger.Log("main", 0, "Network", "Receive Response: {0} {1} {2}", HttpVersion, StatusCode, ReasonPhase); Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Headers = new Dictionary<string, string>();
while (ParseHeader(reader, Headers)) ; while (ParseHeader(reader, Headers)) ;
if (Headers.ContainsKey("content-length")) { if (Headers.ContainsKey("content-length")) {
int length = int.Parse(Headers["content-length"]); int length = int.Parse(Headers["content-length"]);
MessageBody = new HttpResponseBlockStream(reader, length); MessageBody = new Http11ResponseBlockStream(reader, length);
} }
else if (Headers.ContainsKey("transfer-encoding") && Headers["transfer-encoding"] == "chunked") { else if (Headers.ContainsKey("transfer-encoding") && Headers["transfer-encoding"] == "chunked") {
MessageBody = new HttpResponseChunkedStream(reader); MessageBody = new Http11ResponseChunkedStream(reader);
}
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposing) {
if (disposing) {
MessageBody.Dispose();
} }
} }
@@ -36,12 +47,11 @@ namespace Cryville.Common.Network {
// TODO Multiline header // TODO Multiline header
var header = ReadLine(reader); var header = ReadLine(reader);
if (header == "") return false; if (header == "") return false;
var s = header.Split(':'); var s = header.Split(':', 2);
string field_name = s[0].Trim().ToLower(); string field_name = s[0].Trim().ToLower();
string field_value = s[1].Trim(); string field_value = s[1].Trim();
if (headers.ContainsKey(field_name)) headers[field_name] += "," + field_value; if (headers.ContainsKey(field_name)) headers[field_name] += "," + field_value;
else headers.Add(field_name, field_value); else headers.Add(field_name, field_value);
Logger.Log("main", 0, "Network", "Receive Header {0}: {1}", field_name, field_value);
return true; return true;
} }

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: ec18f22479042d747b88c093aa90c5c0 guid: 71234dd1c93d47b4893750686b2333a3
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -4,8 +4,8 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
namespace Cryville.Common.Network { namespace Cryville.Common.Network.Http11 {
public abstract class HttpResponseStream : Stream { public abstract class Http11ResponseStream : Stream {
public override bool CanRead { get { return true; } } public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } } public override bool CanSeek { get { return false; } }
@@ -36,11 +36,11 @@ namespace Cryville.Common.Network {
} }
} }
internal sealed class HttpResponseBlockStream : HttpResponseStream { internal sealed class Http11ResponseBlockStream : Http11ResponseStream {
readonly BinaryReader _reader; readonly BinaryReader _reader;
readonly int _length; readonly int _length;
int _pos = 0; int _pos = 0;
internal HttpResponseBlockStream(BinaryReader reader, int length) { internal Http11ResponseBlockStream(BinaryReader reader, int length) {
_reader = reader; _reader = reader;
_length = length; _length = length;
} }
@@ -50,7 +50,6 @@ namespace Cryville.Common.Network {
if (recv_len == 0) return 0; if (recv_len == 0) return 0;
while (recv < recv_len) { while (recv < recv_len) {
recv += _reader.Read(buffer, offset + recv, count - recv); recv += _reader.Read(buffer, offset + recv, count - recv);
Logger.Log("main", 0, "Network", "Message body received: {0}/{1}/{2}", recv, recv_len, _length);
} }
_pos += recv_len; _pos += recv_len;
return recv_len; return recv_len;
@@ -62,36 +61,34 @@ namespace Cryville.Common.Network {
} }
} }
internal sealed class HttpResponseChunkedStream : HttpResponseStream { internal sealed class Http11ResponseChunkedStream : Http11ResponseStream {
readonly BinaryReader _reader; readonly BinaryReader _reader;
byte[] _chunk = null; byte[] _chunk = null;
int _pos = 0; int _pos = 0;
internal HttpResponseChunkedStream(BinaryReader reader) { internal Http11ResponseChunkedStream(BinaryReader reader) {
_reader = reader; _reader = reader;
ReadChunk(); ReadChunk();
} }
public void ReadChunk() { public void ReadChunk() {
if (_chunk != null && _chunk.Length == 0) return; if (_chunk != null && _chunk.Length == 0) return;
string[] chunkHeader = HttpResponse.ReadLine(_reader).Split(';'); string[] chunkHeader = Http11Response.ReadLine(_reader).Split(';');
// int chunkSize = Array.IndexOf(LEN, chunkHeader[0].ToLower()[0]); int chunkSize;
int chunkSize = int.Parse(chunkHeader[0], NumberStyles.HexNumber); if (!int.TryParse(chunkHeader[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out chunkSize))
if (chunkSize == -1)
throw new IOException("Corrupted chunk received"); throw new IOException("Corrupted chunk received");
if (chunkSize == 0) { if (chunkSize == 0) {
_chunk = new byte[0]; _chunk = new byte[0];
// TODO TE Header, now just discard // TODO TE Header, now just discard
var headers = new Dictionary<string, string>(); var headers = new Dictionary<string, string>();
while (HttpResponse.ParseHeader(_reader, headers)) ; while (Http11Response.ParseHeader(_reader, headers)) ;
return; return;
} }
_chunk = new byte[chunkSize]; _chunk = new byte[chunkSize];
int recv = 0; int recv = 0;
while (recv < chunkSize) { while (recv < chunkSize) {
recv += _reader.Read(_chunk, recv, chunkSize - recv); recv += _reader.Read(_chunk, recv, chunkSize - recv);
Logger.Log("main", 0, "Network", "Message chunk received: {0}/{1}", recv, chunkSize);
} }
_pos = 0; _pos = 0;
if (HttpResponse.ReadLine(_reader) != "") if (Http11Response.ReadLine(_reader) != "")
throw new IOException("Corrupted chunk received"); throw new IOException("Corrupted chunk received");
} }
public override int Read(byte[] buffer, int offset, int count) { public override int Read(byte[] buffer, int offset, int count) {

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: df66519fa93e1b94ea5bb1702cc91b3f guid: 49a8d5b9869e5bb42bafbe71f84fecc5
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -1,8 +1,8 @@
using System; using System;
using System.IO; using System.IO;
namespace Cryville.Common.Network { namespace Cryville.Common.Network.Http11 {
public class HttpsClient : HttpClient { public class Https11Client : Http11Client {
readonly TlsClient _tlsClient; readonly TlsClient _tlsClient;
protected override Stream Stream { protected override Stream Stream {
@@ -16,7 +16,7 @@ namespace Cryville.Common.Network {
} }
} }
public HttpsClient(Uri baseUri) : base(baseUri, 443) { public Https11Client(Uri baseUri) : base(baseUri, 443) {
_tlsClient = new TlsClient(RawTcpStream, baseUri.Host); _tlsClient = new TlsClient(RawTcpStream, baseUri.Host);
} }

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 2b7b45ff20c33ac47b476371673b037c guid: c5c233e6228ce204fa1a9724c48ac8fe
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 5ea931bf5488011468f3d1243a038874
timeCreated: 1622589817
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 07e8215a93e3eb1418685009f0c58dcd
timeCreated: 1622596274
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: f191de447a708da4f9d230e6545ce0a6
timeCreated: 1635470462
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 9b35290e0e147a342acc29a20c8fceaf
timeCreated: 1622503538
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -2,6 +2,7 @@ using Org.BouncyCastle.Security;
using Org.BouncyCastle.Tls; using Org.BouncyCastle.Tls;
using Org.BouncyCastle.Tls.Crypto; using Org.BouncyCastle.Tls.Crypto;
using Org.BouncyCastle.Tls.Crypto.Impl.BC; using Org.BouncyCastle.Tls.Crypto.Impl.BC;
using System;
using System.Collections; using System.Collections;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -9,7 +10,7 @@ using System.Text;
using BcTlsClient = Org.BouncyCastle.Tls.TlsClient; using BcTlsClient = Org.BouncyCastle.Tls.TlsClient;
namespace Cryville.Common.Network { namespace Cryville.Common.Network {
public class TlsClient { public class TlsClient : IDisposable {
readonly TlsClientProtocol _protocol; readonly TlsClientProtocol _protocol;
readonly BcTlsClient _tlsClient; readonly BcTlsClient _tlsClient;
public Stream Stream { get; private set; } public Stream Stream { get; private set; }
@@ -27,6 +28,17 @@ namespace Cryville.Common.Network {
_protocol.Close(); _protocol.Close();
} }
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposing) {
if (disposing) {
Close();
}
}
private class InternalTlsClient : DefaultTlsClient { private class InternalTlsClient : DefaultTlsClient {
readonly string _host; readonly string _host;
@@ -71,20 +83,6 @@ namespace Cryville.Common.Network {
public override TlsAuthentication GetAuthentication() { public override TlsAuthentication GetAuthentication() {
return new NullTlsAuthentication(); return new NullTlsAuthentication();
} }
public override void NotifyAlertReceived(short alertLevel, short alertDescription) {
Logger.Log("main", 0, "Network/TLS", "TLS Alert {0} {1}", alertLevel, alertDescription);
}
public override void NotifyServerVersion(ProtocolVersion serverVersion) {
base.NotifyServerVersion(serverVersion);
Logger.Log("main", 0, "Network/TLS", "NotifyServerVersion {0}", serverVersion);
}
public override void NotifySelectedCipherSuite(int selectedCipherSuite) {
base.NotifySelectedCipherSuite(selectedCipherSuite);
Logger.Log("main", 0, "Network/TLS", "NotifySelectedCipherSuite {0}", selectedCipherSuite);
}
} }
private class NullTlsAuthentication : TlsAuthentication { private class NullTlsAuthentication : TlsAuthentication {

View File

@@ -17,7 +17,6 @@ namespace Cryville.Common.Pdt {
readonly StackFrame[] _stack = new StackFrame[256]; readonly StackFrame[] _stack = new StackFrame[256];
readonly byte[] _mem = new byte[0x100000]; readonly byte[] _mem = new byte[0x100000];
bool _revokepttconst; bool _revokepttconst;
LinkedListNode<PdtInstruction> _ip;
/// <summary> /// <summary>
/// Evaluates an expression and passes the result to a target operator. /// Evaluates an expression and passes the result to a target operator.
/// </summary> /// </summary>
@@ -25,25 +24,23 @@ namespace Cryville.Common.Pdt {
/// <param name="exp">The expression to evaluate.</param> /// <param name="exp">The expression to evaluate.</param>
/// <returns>Whether the evaluaton succeeded.</returns> /// <returns>Whether the evaluaton succeeded.</returns>
public bool Evaluate(PdtOperator target, PdtExpression exp) { public bool Evaluate(PdtOperator target, PdtExpression exp) {
_framecount = 0; var prevFrameCount = _framecount;
_goffset = 0; try {
_revokepttconst = false; _revokepttconst = false;
for (_ip = exp.Instructions.First; _ip != null; _ip = _ip.Next) for (var ip = exp.Instructions.First; ip != null; ip = ip.Next)
_ip.Value.Execute(this); ip.Value.Execute(this, ref ip);
if (exp.IsPotentialConstant) { if (exp.IsPotentialConstant) {
exp.IsConstant = exp.IsPotentialConstant = !_revokepttconst; exp.IsConstant = exp.IsPotentialConstant = !_revokepttconst;
} }
return Operate(target, _framecount, true); var ret = Operate(target, _framecount - prevFrameCount, true);
return ret;
}
catch (Exception ex) {
throw new EvaluationFailureException(exp, ex);
}
finally {
for (var i = prevFrameCount; i < _framecount; i++) DiscardStack();
} }
/// <summary>
/// Patches an expression with a lefthand variable and a compound operator.
/// </summary>
/// <param name="target">The name of the lefthand variable.</param>
/// <param name="op">The name of the compound operator.</param>
/// <param name="exp">The expression.</param>
public void PatchCompound(int target, int op, PdtExpression exp) {
exp.Instructions.AddFirst(new PdtInstruction.PushVariable(target));
exp.Instructions.AddLast(new PdtInstruction.Operate(op, 2));
} }
/// <summary> /// <summary>
/// Optimizes an expression by merging its instructions. /// Optimizes an expression by merging its instructions.
@@ -55,14 +52,14 @@ namespace Cryville.Common.Pdt {
List<PdtInstruction.Collapse> ct; List<PdtInstruction.Collapse> ct;
var cols = new Dictionary<LinkedListNode<PdtInstruction>, List<PdtInstruction.Collapse>>(); var cols = new Dictionary<LinkedListNode<PdtInstruction>, List<PdtInstruction.Collapse>>();
var il = exp.Instructions; var il = exp.Instructions;
_ip = il.First; var ip = il.First;
while (_ip != null) { while (ip != null) {
bool nextFlag = false; bool nextFlag = false;
var i = _ip.Value; var i = ip.Value;
if (i is PdtInstruction.Operate) { if (i is PdtInstruction.Operate) {
int fc0 = _framecount; int fc0 = _framecount;
int fc1 = ((PdtInstruction.Operate)i).Signature.ParamCount; int fc1 = ((PdtInstruction.Operate)i).Signature.ParamCount;
try { i.Execute(this); } catch (Exception) { } try { i.Execute(this, ref ip); } catch (Exception) { }
if (fc0 - _framecount == fc1) { if (fc0 - _framecount == fc1) {
unsafe { unsafe {
fixed (StackFrame* frame = &_stack[_framecount++]) { fixed (StackFrame* frame = &_stack[_framecount++]) {
@@ -74,36 +71,38 @@ namespace Cryville.Common.Pdt {
} }
else { else {
var frame = _stack[_framecount - 1]; var frame = _stack[_framecount - 1];
ReplaceIP(il, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length), cols); if (frame.Type != PdtInternalType.Error) {
for (var j = 0; j < fc1; j++) il.Remove(_ip.Previous); ReplaceIP(il, ref ip, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length), cols);
for (var j = 0; j < fc1; j++) il.Remove(ip.Previous);
}
} }
} }
else if (i is PdtInstruction.Collapse) { else if (i is PdtInstruction.Collapse) {
var t = (PdtInstruction.Collapse)i; var t = (PdtInstruction.Collapse)i;
try { try {
var pins = _ip; var pins = ip;
i.Execute(this); i.Execute(this, ref ip);
if (_stack[_framecount - 1].Type == PdtInternalType.Error) { if (_stack[_framecount - 1].Type == PdtInternalType.Error) {
throw new EvaluationFailureException(); throw new EvaluationFailureException();
} }
if (_ip == pins) { if (ip == pins) {
_ip = _ip.Next; ip = ip.Next;
il.Remove(_ip.Previous); il.Remove(ip.Previous);
il.Remove(_ip.Previous); il.Remove(ip.Previous);
_ip = _ip.Previous; ip = ip.Previous;
if (_ip == null) { if (ip == null) {
_ip = il.First; ip = il.First;
nextFlag = true; nextFlag = true;
} }
} }
else { else {
_ip = pins.Previous; ip = pins.Previous;
while (_ip.Next != t.Target) il.Remove(_ip.Next); while (ip.Next != t.Target) il.Remove(ip.Next);
il.Remove(_ip.Next); il.Remove(ip.Next);
if (cols.TryGetValue(t.Target, out ct)) { if (cols.TryGetValue(t.Target, out ct)) {
foreach (var u in ct) u.Target = _ip; foreach (var u in ct) u.Target = ip;
cols.Remove(t.Target); cols.Remove(t.Target);
cols.Add(_ip, ct); cols.Add(ip, ct);
} }
} }
} }
@@ -113,14 +112,14 @@ namespace Cryville.Common.Pdt {
} }
} }
else if (i is PdtInstruction.PushVariable) { else if (i is PdtInstruction.PushVariable) {
i.Execute(this); i.Execute(this, ref ip);
var frame = _stack[_framecount - 1]; var frame = _stack[_framecount - 1];
if (frame.Type != PdtInternalType.Undefined && frame.Type != PdtInternalType.Error) { if (frame.Type != PdtInternalType.Undefined && frame.Type != PdtInternalType.Error) {
ReplaceIP(il, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length), cols); ReplaceIP(il, ref ip, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length), cols);
} }
} }
else i.Execute(this); else i.Execute(this, ref ip);
if (_ip != null && cols.TryGetValue(_ip, out ct)) { if (ip != null && cols.TryGetValue(ip, out ct)) {
unsafe { unsafe {
fixed (StackFrame* frame = &_stack[_framecount - 1]) { fixed (StackFrame* frame = &_stack[_framecount - 1]) {
frame->Type = PdtInternalType.Error; frame->Type = PdtInternalType.Error;
@@ -129,26 +128,23 @@ namespace Cryville.Common.Pdt {
} }
} }
} }
if (!nextFlag) _ip = _ip.Next; if (!nextFlag) ip = ip.Next;
} }
exp.IsConstant = true; exp.IsConstant = true;
exp.IsPotentialConstant = true; exp.IsPotentialConstant = true;
for (var ins = il.First; ins != null; ins = ins.Next) { for (var ins = il.First; ins != null; ins = ins.Next) {
if (!(ins.Value is PdtInstruction.PushConstant)) { if (!(ins.Value is PdtInstruction.PushConstant)) {
exp.IsConstant = false; exp.IsConstant = false;
} break;
else if (!(ins.Value is PdtInstruction.PushVariable)) {
exp.IsPotentialConstant = false;
return;
} }
} }
} }
void ReplaceIP(LinkedList<PdtInstruction> il, PdtInstruction ins, Dictionary<LinkedListNode<PdtInstruction>, List<PdtInstruction.Collapse>> cols) { void ReplaceIP(LinkedList<PdtInstruction> il, ref LinkedListNode<PdtInstruction> ip, PdtInstruction ins, Dictionary<LinkedListNode<PdtInstruction>, List<PdtInstruction.Collapse>> cols) {
List<PdtInstruction.Collapse> cins; List<PdtInstruction.Collapse> cins;
if (cols.TryGetValue(_ip, out cins)) cols.Remove(_ip); if (cols.TryGetValue(ip, out cins)) cols.Remove(ip);
_ip = il.AddAfter(_ip, ins); ip = il.AddAfter(ip, ins);
il.Remove(_ip.Previous); il.Remove(ip.Previous);
if (cins != null) cols.Add(_ip, cins); if (cins != null) cols.Add(ip, cins);
} }
/// <summary> /// <summary>
/// Revokes the potential constant mark of the current expression. /// Revokes the potential constant mark of the current expression.
@@ -207,8 +203,8 @@ namespace Cryville.Common.Pdt {
for (int i = 0; i < pc; i++) { for (int i = 0; i < pc; i++) {
var frame = _stack[--_framecount]; var frame = _stack[--_framecount];
if (frame.Type == PdtInternalType.Error) { if (frame.Type == PdtInternalType.Error) {
_framecount -= pc - i; _framecount -= pc - i - 1;
_stack[_framecount++] = new StackFrame { Type = PdtInternalType.Error, Offset = _goffset, Length = 0 }; _stack[_framecount++] = new StackFrame { Type = PdtInternalType.Error, Offset = -1, Length = 0 };
return false; return false;
} }
op.LoadOperand(new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length)); op.LoadOperand(new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length));
@@ -218,17 +214,19 @@ namespace Cryville.Common.Pdt {
return true; return true;
} }
} }
internal unsafe void Collapse(int name, LinkedListNode<PdtInstruction> target) { internal unsafe void Collapse(int name, ref LinkedListNode<PdtInstruction> self, LinkedListNode<PdtInstruction> target) {
fixed (byte* pmem = _mem) { fixed (byte* pmem = _mem) {
var frame = _stack[--_framecount]; var frame = _stack[--_framecount];
_goffset -= frame.Length;
if (frame.Type == PdtInternalType.Error) { if (frame.Type == PdtInternalType.Error) {
_stack[_framecount++] = new StackFrame { Type = PdtInternalType.Error, Offset = _goffset, Length = 0 }; _stack[_framecount++] = new StackFrame { Type = PdtInternalType.Error, Offset = -1, Length = 0 };
_ip = target; self = target;
return; return;
} }
if (Collapse(name, new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length))) { if (Collapse(name, new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length))) {
_framecount++; _framecount++;
_ip = target; _goffset += frame.Length;
self = target;
} }
} }
} }
@@ -265,5 +263,16 @@ namespace Cryville.Common.Pdt {
public EvaluationFailureException(string message, Exception innerException) : base(message, innerException) { } public EvaluationFailureException(string message, Exception innerException) : base(message, innerException) { }
/// <inheritdoc /> /// <inheritdoc />
protected EvaluationFailureException(SerializationInfo info, StreamingContext context) : base(info, context) { } protected EvaluationFailureException(SerializationInfo info, StreamingContext context) : base(info, context) { }
/// <summary>
/// Creates an instance of the <see cref="EvaluationFailureException" /> class with the failing expression.
/// </summary>
/// <param name="exp">The failing expression.</param>
public EvaluationFailureException(PdtExpression exp) : base("Evaluation failed for the expression: " + exp.ToString()) { }
/// <summary>
/// Creates an instance of the <see cref="EvaluationFailureException" /> class with the failing expression and the inner exception.
/// </summary>
/// <param name="exp">The failing expression.</param>
/// <param name="innerException">The inner exception.</param>
public EvaluationFailureException(PdtExpression exp, Exception innerException) : base("Evaluation failed for the expression: " + exp.ToString(), innerException) { }
} }
} }

View File

@@ -7,6 +7,18 @@ namespace Cryville.Common.Pdt {
/// PDT expression. /// PDT expression.
/// </summary> /// </summary>
public class PdtExpression { public class PdtExpression {
/// <summary>
/// The empty expression.
/// </summary>
public static readonly PdtExpression Empty;
static PdtExpression() {
var ins = new LinkedList<PdtInstruction>();
ins.AddLast(new PdtInstruction.PushConstant(
PdtInternalType.Number, BitConverter.GetBytes(1f)
));
Empty = new PdtExpression(ins);
}
internal LinkedList<PdtInstruction> Instructions; internal LinkedList<PdtInstruction> Instructions;
/// <summary> /// <summary>
/// Whether the value of this expression is constant. /// Whether the value of this expression is constant.
@@ -27,9 +39,19 @@ namespace Cryville.Common.Pdt {
} }
return r; return r;
} }
/// <summary>
/// Patches an expression with a lefthand variable and a compound operator.
/// </summary>
/// <param name="target">The name of the lefthand variable.</param>
/// <param name="op">The name of the compound operator.</param>
/// <param name="exp">The expression.</param>
public static void PatchCompound(int target, int op, PdtExpression exp) {
exp.Instructions.AddFirst(new PdtInstruction.PushVariable(target));
exp.Instructions.AddLast(new PdtInstruction.Operate(op, 2));
}
} }
internal abstract class PdtInstruction { internal abstract class PdtInstruction {
internal abstract void Execute(PdtEvaluatorBase etor); internal abstract void Execute(PdtEvaluatorBase etor, ref LinkedListNode<PdtInstruction> self);
public class PushConstant : PdtInstruction { public class PushConstant : PdtInstruction {
public int Type { get; private set; } public int Type { get; private set; }
public byte[] Value { get; private set; } public byte[] Value { get; private set; }
@@ -42,7 +64,7 @@ namespace Cryville.Common.Pdt {
Value = new byte[len]; Value = new byte[len];
Array.Copy(buffer, offset, Value, 0, len); Array.Copy(buffer, offset, Value, 0, len);
} }
internal override void Execute(PdtEvaluatorBase etor) { internal override void Execute(PdtEvaluatorBase etor, ref LinkedListNode<PdtInstruction> self) {
etor.PushConstant(Type, Value); etor.PushConstant(Type, Value);
} }
public override string ToString() { public override string ToString() {
@@ -53,12 +75,12 @@ namespace Cryville.Common.Pdt {
public int Name { get; private set; } public int Name { get; private set; }
public bool Forced { get; private set; } public bool Forced { get; private set; }
public PushVariable(int name, bool forced = false) { Name = name; Forced = forced; } public PushVariable(int name, bool forced = false) { Name = name; Forced = forced; }
public PushVariable(string name, bool forced = false) : this(IdentifierManager.SharedInstance.Request(name)) { Forced = forced; } public PushVariable(string name, bool forced = false) : this(IdentifierManager.Shared.Request(name)) { Forced = forced; }
internal override void Execute(PdtEvaluatorBase etor) { internal override void Execute(PdtEvaluatorBase etor, ref LinkedListNode<PdtInstruction> self) {
etor.PushVariable(Name, Forced); etor.PushVariable(Name, Forced);
} }
public override string ToString() { public override string ToString() {
return string.Format(Forced ? "pushv ?{0}" : "pushv {0}", IdentifierManager.SharedInstance.Retrieve(Name)); return string.Format(Forced ? "pushv ?{0}" : "pushv {0}", IdentifierManager.Shared.Retrieve(Name));
} }
} }
public class Operate : PdtInstruction { public class Operate : PdtInstruction {
@@ -69,7 +91,7 @@ namespace Cryville.Common.Pdt {
public Operate(string name, int paramCount) { public Operate(string name, int paramCount) {
Signature = new PdtOperatorSignature(name, paramCount); Signature = new PdtOperatorSignature(name, paramCount);
} }
internal override void Execute(PdtEvaluatorBase etor) { internal override void Execute(PdtEvaluatorBase etor, ref LinkedListNode<PdtInstruction> self) {
etor.Operate(Signature); etor.Operate(Signature);
} }
public override string ToString() { public override string ToString() {
@@ -80,14 +102,14 @@ namespace Cryville.Common.Pdt {
public int Name { get; private set; } public int Name { get; private set; }
public LinkedListNode<PdtInstruction> Target { get; internal set; } public LinkedListNode<PdtInstruction> Target { get; internal set; }
public Collapse(string name, LinkedListNode<PdtInstruction> target) { public Collapse(string name, LinkedListNode<PdtInstruction> target) {
Name = IdentifierManager.SharedInstance.Request(name); Name = IdentifierManager.Shared.Request(name);
Target = target; Target = target;
} }
internal override void Execute(PdtEvaluatorBase etor) { internal override void Execute(PdtEvaluatorBase etor, ref LinkedListNode<PdtInstruction> self) {
etor.Collapse(Name, Target); etor.Collapse(Name, ref self, Target);
} }
public override string ToString() { public override string ToString() {
return string.Format("col {0}{{{1}}}", IdentifierManager.SharedInstance.Retrieve(Name), Target.Value); return string.Format("col {0}{{{1}}}", IdentifierManager.Shared.Retrieve(Name), Target.Value);
} }
} }
} }
@@ -115,15 +137,6 @@ namespace Cryville.Common.Pdt {
{ '$', -1 }, { '$', -1 },
}; };
static readonly PdtExpression _emptyexp;
static PdtInterpreter() {
var ins = new LinkedList<PdtInstruction>();
ins.AddLast(new PdtInstruction.PushConstant(
PdtInternalType.Number, BitConverter.GetBytes(1f)
));
_emptyexp = new PdtExpression(ins);
}
PdtExpToken GetToken() { PdtExpToken GetToken() {
ws(); ws();
var result = new PdtExpToken { var result = new PdtExpToken {

Some files were not shown because too many files have changed in this diff Show More