2014-11-01 14:43:50 +01:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2014-11-05 22:39:31 +01:00
|
|
|
using System.IO;
|
|
|
|
|
using System.IO.Compression;
|
2014-11-01 14:43:50 +01:00
|
|
|
using System.Linq;
|
2014-11-05 22:39:31 +01:00
|
|
|
using System.Net.Http;
|
2014-11-01 14:43:50 +01:00
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
2014-11-03 00:05:54 +01:00
|
|
|
namespace System.Unicode.Builder
|
2014-11-01 14:43:50 +01:00
|
|
|
{
|
2014-11-05 22:39:31 +01:00
|
|
|
internal class Program
|
2014-11-01 14:43:50 +01:00
|
|
|
{
|
2017-06-25 17:14:03 +02:00
|
|
|
public static readonly Uri UnicodeCharacterDataUri = new Uri("http://www.unicode.org/Public/UCD/latest/ucd/", UriKind.Absolute);
|
|
|
|
|
public static readonly Uri EmojiDataUri = new Uri("http://www.unicode.org/Public/emoji/latest/", UriKind.Absolute);
|
|
|
|
|
|
2014-11-08 22:00:12 +01:00
|
|
|
public const string UnihanDirectoryName = "Unihan";
|
|
|
|
|
public const string UnihanArchiveName = "Unihan.zip";
|
2014-11-17 23:29:51 +01:00
|
|
|
public const string UcdDirectoryName = "UCD";
|
2014-11-05 22:39:31 +01:00
|
|
|
public const string UcdArchiveName = "UCD.zip";
|
|
|
|
|
|
|
|
|
|
public static readonly string[] ucdRequiredFiles = new[]
|
2014-11-03 00:05:54 +01:00
|
|
|
{
|
2014-11-05 22:39:31 +01:00
|
|
|
"UnicodeData.txt",
|
|
|
|
|
"PropList.txt",
|
2014-11-08 22:00:12 +01:00
|
|
|
"DerivedCoreProperties.txt",
|
2014-11-24 20:09:59 +01:00
|
|
|
"CJKRadicals.txt",
|
2014-11-24 00:24:55 +01:00
|
|
|
//"Jamo.txt", // Not used right now, as the hangul syllable algorithm implementation takes care of this.
|
|
|
|
|
"NameAliases.txt",
|
|
|
|
|
"NamesList.txt",
|
2014-11-16 21:27:57 +01:00
|
|
|
"Blocks.txt",
|
2014-11-05 22:39:31 +01:00
|
|
|
};
|
|
|
|
|
|
2014-11-15 00:58:03 +01:00
|
|
|
public static readonly string[] unihanRequiredFiles = new[]
|
|
|
|
|
{
|
|
|
|
|
"Unihan_NumericValues.txt",
|
|
|
|
|
"Unihan_Readings.txt",
|
|
|
|
|
"Unihan_Variants.txt",
|
2014-11-24 02:36:09 +01:00
|
|
|
"Unihan_IRGSources.txt",
|
2014-11-15 00:58:03 +01:00
|
|
|
};
|
|
|
|
|
|
2017-06-25 17:14:03 +02:00
|
|
|
public static readonly string[] emojiRequiredFiles = new[]
|
|
|
|
|
{
|
|
|
|
|
"emoji-data.txt",
|
|
|
|
|
"emoji-sequences.txt",
|
|
|
|
|
"emoji-variation-sequences.txt",
|
|
|
|
|
"emoji-zwj-sequences.txt",
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-19 01:54:17 +02:00
|
|
|
private static HttpClient httpClient;
|
2014-11-17 23:29:51 +01:00
|
|
|
|
|
|
|
|
// The only purpose of this is for tests…
|
2015-07-19 01:54:17 +02:00
|
|
|
internal static void SetHttpMessageHandler(HttpMessageHandler handler)
|
2014-11-17 23:29:51 +01:00
|
|
|
{
|
2015-07-19 01:54:17 +02:00
|
|
|
httpClient = new HttpClient(handler ?? new HttpClientHandler());
|
2014-11-03 00:05:54 +01:00
|
|
|
}
|
2014-11-05 22:39:31 +01:00
|
|
|
|
2017-06-25 17:14:03 +02:00
|
|
|
internal static HttpClient HttpClient { get { return httpClient ?? (httpClient = new HttpClient()); } }
|
|
|
|
|
|
|
|
|
|
private static Task<byte[]> DownloadDataArchiveAsync(string archiveName)
|
|
|
|
|
=> HttpClient.GetByteArrayAsync(UnicodeCharacterDataUri + archiveName);
|
|
|
|
|
|
|
|
|
|
internal static async Task<IDataSource> GetDataSourceAsync(string archiveName, string directoryName, string[] requiredFiles, bool? shouldDownload, bool? shouldSaveArchive, bool? shouldExtract)
|
2014-11-05 22:39:31 +01:00
|
|
|
{
|
2017-06-21 02:28:58 +02:00
|
|
|
string baseDirectory = Directory.GetCurrentDirectory();
|
2014-11-17 23:29:51 +01:00
|
|
|
string dataDirectory = Path.Combine(baseDirectory, UcdDirectoryName);
|
2014-11-15 00:58:03 +01:00
|
|
|
string dataArchiveFileName = Path.Combine(baseDirectory, archiveName);
|
2014-11-05 22:39:31 +01:00
|
|
|
|
|
|
|
|
if (shouldDownload != true)
|
|
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
bool hasValidDirectory = Directory.Exists(dataDirectory);
|
2014-11-05 22:39:31 +01:00
|
|
|
|
|
|
|
|
if (hasValidDirectory)
|
|
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
foreach (string requiredFile in requiredFiles)
|
2014-11-05 22:39:31 +01:00
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
if (!File.Exists(Path.Combine(dataDirectory, requiredFile)))
|
2014-11-05 22:39:31 +01:00
|
|
|
{
|
|
|
|
|
hasValidDirectory = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasValidDirectory)
|
|
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
return new FileDataSource(dataDirectory);
|
2014-11-05 22:39:31 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-15 00:58:03 +01:00
|
|
|
if (File.Exists(dataArchiveFileName))
|
2014-11-05 22:39:31 +01:00
|
|
|
{
|
|
|
|
|
if (shouldExtract == true)
|
|
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
ZipFile.ExtractToDirectory(dataArchiveFileName, dataDirectory);
|
|
|
|
|
return new FileDataSource(dataDirectory);
|
2014-11-05 22:39:31 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
return new ZipDataSource(File.OpenRead(dataArchiveFileName));
|
2014-11-05 22:39:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-11-16 21:27:57 +01:00
|
|
|
}
|
2014-11-05 22:39:31 +01:00
|
|
|
|
|
|
|
|
if (shouldDownload != false)
|
|
|
|
|
{
|
2017-06-25 17:14:03 +02:00
|
|
|
var dataArchiveData = await DownloadDataArchiveAsync(archiveName).ConfigureAwait(false);
|
2014-11-05 22:39:31 +01:00
|
|
|
|
|
|
|
|
if (shouldSaveArchive == true)
|
|
|
|
|
{
|
2017-06-25 17:14:03 +02:00
|
|
|
using (var stream = File.Open(dataArchiveFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
|
2014-11-05 22:39:31 +01:00
|
|
|
{
|
2017-06-25 17:14:03 +02:00
|
|
|
await stream.WriteAsync(dataArchiveData, 0, dataArchiveData.Length).ConfigureAwait(false);
|
|
|
|
|
dataArchiveData = null; // Release the reference now, since we won't need it anymore.
|
2014-11-05 22:39:31 +01:00
|
|
|
|
|
|
|
|
if (shouldExtract == true)
|
|
|
|
|
{
|
|
|
|
|
using (var archive = new ZipArchive(stream, ZipArchiveMode.Read, false))
|
|
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
archive.ExtractToDirectory(dataDirectory);
|
2014-11-05 22:39:31 +01:00
|
|
|
|
2014-11-15 00:58:03 +01:00
|
|
|
return new FileDataSource(dataDirectory);
|
2014-11-05 22:39:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
return new ZipDataSource(stream);
|
2014-11-05 22:39:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-11-15 00:58:03 +01:00
|
|
|
return new ZipDataSource(new MemoryStream(dataArchiveData));
|
2014-11-05 22:39:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new InvalidOperationException();
|
2014-11-16 21:27:57 +01:00
|
|
|
}
|
2014-11-05 22:39:31 +01:00
|
|
|
|
2017-06-25 17:14:03 +02:00
|
|
|
private static async Task MainAsync(string[] args)
|
2014-11-05 22:39:31 +01:00
|
|
|
{
|
2014-11-08 01:43:17 +01:00
|
|
|
UnicodeInfoBuilder data;
|
2014-11-05 22:39:31 +01:00
|
|
|
|
2017-06-25 17:14:03 +02:00
|
|
|
using (var ucdSource = await GetDataSourceAsync(UcdArchiveName, UcdDirectoryName, ucdRequiredFiles, null, null, null))
|
|
|
|
|
using (var unihanSource = await GetDataSourceAsync(UnihanArchiveName, UnihanDirectoryName, unihanRequiredFiles, null, null, null))
|
|
|
|
|
using (var emojiSource = new HttpDataSource(EmojiDataUri, HttpClient))
|
2014-11-05 22:39:31 +01:00
|
|
|
{
|
2017-06-25 17:14:03 +02:00
|
|
|
data = await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource, emojiSource);
|
2014-11-05 22:39:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
|
|
|
|
|
data.WriteToStream(stream);
|
2014-11-16 21:27:57 +01:00
|
|
|
}
|
2017-06-25 17:14:03 +02:00
|
|
|
|
|
|
|
|
private static void Main(string[] args) => MainAsync(args).Wait();
|
2014-11-01 14:43:50 +01:00
|
|
|
}
|
|
|
|
|
}
|