/// <summary> /// Gets the current build number. /// </summary> /// <returns>The current build number.</returns> public static FontBuildNumber GetCurrentBuildNumber() { const string BuildNumberKey = "FontBuildNumber"; string value = Environment.GetEnvironmentVariable(BuildNumberKey, EnvironmentVariableTarget.Process); FontBuildNumber current = new FontBuildNumber(); if (!string.IsNullOrEmpty(value)) { // Gets the current build number from environment successfully. current.Parse(value); } else { // Fails to get the build number from environment setting, creates one according to the time. current.MajorBuildNumber = (((DateTime.Now.Year - 2000) % 5) * 10000) + (DateTime.Now.Month * 100) + DateTime.Now.Day; current.MinorBuildNumber = (DateTime.Now.Hour * 100) + DateTime.Now.Minute; } return current; }
/// <summary> /// Save weight table to apl file. /// </summary> /// <param name="filePath">The target location of the file to save into.</param> public void SaveAsApl(string filePath) { FontBuildNumber buildNumber = new FontBuildNumber(); SaveAsApl(filePath, buildNumber); }
/// <summary> /// Loads the header section from binary reader. /// </summary> /// <param name="reader">The given binary reader.</param> private void LoadHeader(BinaryReader reader) { uint uintData = reader.ReadUInt32(); if (uintData != FileTag) { byte[] bytes = Helper.ToBytes(uintData); Debug.Assert(bytes.Length == 4, "uint is 4 bytes length"); throw new InvalidDataException(Helper.NeutralFormat( "Unsupported file tag \"0x{0}, 0x{1}, 0x{2}, 0x{3}\"", bytes[0].ToString("x", CultureInfo.InvariantCulture), bytes[1].ToString("x", CultureInfo.InvariantCulture), bytes[2].ToString("x", CultureInfo.InvariantCulture), bytes[3].ToString("x", CultureInfo.InvariantCulture))); } Guid guid = new Guid(reader.ReadBytes(FormatTag.ToByteArray().Length)); if (guid != FormatTag) { throw new InvalidDataException(Helper.NeutralFormat("Unsupported GUID \"{0}\"", guid.ToString("D", CultureInfo.InvariantCulture))); } DataSize = reader.ReadUInt32(); if (DataSize != reader.BaseStream.Length - reader.BaseStream.Position) { throw new InvalidDataException("Input stream is corrupt since data size is mismatched"); } uintData = reader.ReadUInt32(); if (uintData != Version) { throw new InvalidDataException("Unspported version"); } BuildNumber = new FontBuildNumber(reader.ReadInt32()); SamplePerFrame = reader.ReadUInt32(); UnitIndexOffset = reader.ReadUInt32(); UnitIndexCount = reader.ReadUInt32(); CandidateDataOffset = reader.ReadUInt32(); CandidateCount = reader.ReadUInt32(); StringPoolOffset = reader.ReadUInt32(); StringPoolSize = reader.ReadUInt32(); }
/// <summary> /// Save weight table to apl file. /// </summary> /// <param name="filePath">Target file path to save weight table data.</param> /// <param name="buildNumber">Voice font build number.</param> public void SaveAsApl(string filePath, FontBuildNumber buildNumber) { Helper.EnsureFolderExistForFile(filePath); if (buildNumber == null) { throw new ArgumentNullException("buildNumber"); } FileStream fs = new FileStream(filePath, FileMode.Create); try { using (BinaryWriter bw = new BinaryWriter(fs)) { fs = null; uint size = (uint)Marshal.SizeOf(typeof(WeightTableHeaderSerial)); // Write header WeightTableHeaderSerial aplHeader = new WeightTableHeaderSerial(); aplHeader.Tag = (uint)FontSectionTag.WeightTable; ////sizeFieldOffset = sizeof(aplHeader.Tag + aplHeader.FormatTag) int sizeFieldOffset = sizeof(uint) + aplHeader.FormatTag.Length; aplHeader.Size = 0; // Update after all other sections have been written. aplHeader.Version = (uint)FormatVersion.Tts30; aplHeader.Build = (uint)buildNumber.ToInt32(); aplHeader.LangNumber = 1; aplHeader.DataOffset = size; bw.Write(aplHeader.ToBytes()); // Write Section size += SaveSection(bw); // Update "size" field in the header to sizeof(Tag + FormatTag + Size). size -= sizeof(uint) + sizeof(uint) + (uint)aplHeader.FormatTag.Length; bw.Seek(sizeFieldOffset, SeekOrigin.Begin); bw.Write(size); } } finally { if (null != fs) { fs.Dispose(); } } }
/// <summary> /// Save domain index file. /// </summary> /// <param name="filePath">File path.</param> /// <param name="buildNumber">Build number.</param> public void Save(string filePath, FontBuildNumber buildNumber) { // Header size int headerSize = Marshal.SizeOf(typeof(DomainIndexFileHeaderSerial)); // Hash table size // One hash table item // 1. Offset in string pool (uint) // 2. Offset in feature data (uint) // 3. Index of next item in hash table (int) int hashTableSize = _items.Length * (sizeof(uint) + sizeof(uint) + sizeof(int)); // Feature data size & string pool size int featureDataSize = 0; int stringPoolSize = 0; for (int i = 0; i < _items.Length; i++) { Debug.Assert(_items[i] != null); featureDataSize += _items[i].FeatureItemBinarySize; stringPoolSize += _items[i].StringBinarySize; } DomainIndexFileHeaderSerial header; header.Tag = (uint)_tag; header.Size = (uint)(headerSize - 8 + hashTableSize + featureDataSize + stringPoolSize); header.VersionNumber = (uint)FormatVersion.Tts30; header.BuildNumber = (uint)buildNumber.ToInt32(); header.LanguageId = (uint)_language; header.HashTableItemCount = _items.Length; header.HashTableOffset = headerSize; header.HashTableSize = hashTableSize; header.FeatureDataOffset = header.HashTableOffset + hashTableSize; header.FeatureDataSize = featureDataSize; header.StringPoolOffset = header.FeatureDataOffset + featureDataSize; header.StringPoolSize = stringPoolSize; FileStream fs = new FileStream(filePath, FileMode.Create); try { using (BinaryWriter bw = new BinaryWriter(fs)) { fs = null; // Write header bw.Write(header.ToBytes()); // Write hash table foreach (DomainIndexItem item in _items) { item.WriteHashtable(bw); } // Write feature data foreach (DomainIndexItem item in _items) { item.WriteFeatureData(bw); } // Write string pool foreach (DomainIndexItem item in _items) { item.WriteWordText(bw); } } } finally { if (null != fs) { fs.Dispose(); } } }