/// <summary>
        /// Create language data file.
        /// </summary>
        /// <param name="fileName">Language data file name.</param>
        /// <param name="domain">Domain.</param>
        /// <returns>Errors.</returns>
        public ErrorSet CombineDataFile(string fileName, string domain)
        {
            if (string.IsNullOrEmpty(domain) || string.IsNullOrEmpty(domain.Trim()))
            {
                domain = DomainItem.GeneralDomain;
            }

            ErrorSet errorSet = new ErrorSet();

            if (domain.Equals(DomainItem.GeneralDomain, StringComparison.OrdinalIgnoreCase))
            {
                errorSet = EnsureNecessaryData(this._moduleDataSet);
            }
            else if (this._moduleDataSet.Count == 0)
            {
                errorSet.Add(new Error(DataCompilerError.DomainDataMissing, domain));
            }

            if (!errorSet.Contains(ErrorSeverity.MustFix))
            {
                using (LangDataFile langDataFile = new LangDataFile())
                {
                    // Set file property
                    FileProperty fileProperty = new FileProperty();
                    fileProperty.Version = 1;
                    fileProperty.Build = 0;
                    fileProperty.LangID = (uint)_language;
                    langDataFile.FileProperties = fileProperty;

                    ArrayList sortedDataObjects = new ArrayList();
                    foreach (KeyValuePair<string, LangDataObject> obj in _moduleDataSet)
                    {
                        sortedDataObjects.Add(obj);
                    }

                    sortedDataObjects.Sort(new CompareLangDataObject());

                    // Set data objects
                    foreach (KeyValuePair<string, LangDataObject> obj in sortedDataObjects)
                    {
                        if (obj.Value.Data == null)
                        {
                            continue;
                        }

                        langDataFile.AddDataObject(obj.Value);
                        string message = Helper.NeutralFormat("Added {{{0}}} ({1}) data.",
                            obj.Value.Token.ToString(), obj.Key);
                        errorSet.Add(new Error(DataCompilerError.CompilingLog, message));
                    }

                    // Save as binary file
                    Helper.EnsureFolderExistForFile(fileName);
                    langDataFile.Save(fileName);
                }
            }

            return errorSet;
        }
        /// <summary>
        /// Merge compiling error into main error set.
        /// </summary>
        /// <param name="mainErrorSet">Main error set.</param>
        /// <param name="subErrorSet">Sub error set.</param>
        /// <param name="dataName">Data name.</param>
        private static void MergeDependencyError(ErrorSet mainErrorSet, ErrorSet subErrorSet, string dataName)
        {
            if (mainErrorSet == null)
            {
                throw new ArgumentNullException("mainErrorSet");
            }

            if (subErrorSet == null)
            {
                throw new ArgumentNullException("subErrorSet");
            }

            if (string.IsNullOrEmpty(dataName))
            {
                throw new ArgumentNullException("dataName");
            }

            if (subErrorSet.Contains(ErrorSeverity.MustFix))
            {
                mainErrorSet.Add(DataCompilerError.DependenciesNotValid, dataName);
            }

            foreach (Error error in subErrorSet.Errors)
            {
                if (error.Severity == ErrorSeverity.MustFix)
                {
                    mainErrorSet.Add(DataCompilerError.CompilingLogWithError, dataName, error.ToString());
                }
                else if (error.Severity == ErrorSeverity.Warning)
                {
                    mainErrorSet.Add(DataCompilerError.CompilingLogWithWarning, dataName, error.ToString());
                }
                else if (error.Severity == ErrorSeverity.NoError)
                {
                    mainErrorSet.Add(DataCompilerError.CompilingLogWithDataName, dataName, error.ToString());
                }
            }
        }
        /// <summary>
        /// Char table compiler.
        /// </summary>
        /// <param name="outputStream">Output Stream.</param>
        /// <returns>ErrorSet.</returns>
        private ErrorSet CompileCharTable(Stream outputStream)
        {
            ErrorSet errorSet = new ErrorSet();

            try
            {
                CharTable charTable = (CharTable)GetObject(RawDataName.CharTable, errorSet);

                ChartableValidator charTableValidator = new ChartableValidator();
                Microsoft.Tts.Offline.Core.Lexicon lexicon = (Microsoft.Tts.Offline.Core.Lexicon)GetObject(RawDataName.Lexicon, errorSet);
                TtsPhoneSet phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, errorSet);
                if (!errorSet.Contains(ErrorSeverity.MustFix))
                {
                    charTableValidator.Lexicon = lexicon;
                    charTableValidator.PhoneSet = phoneSet;
                    charTableValidator.EnsureInitialized();

                    if (charTable.Language != charTableValidator.Language)
                    {
                        throw new InvalidDataException("chartable language should match with lexicon or phoneset");
                    }

                    ErrorSet charTableErrors = charTableValidator.Validate(charTable, false, null);
                    foreach (Error error in charTableErrors.Errors)
                    {
                        if (error.Severity == ErrorSeverity.MustFix)
                        {
                            errorSet.Add(DataCompilerError.CompilingLogWithError,
                                RawDataName.CharTable, error.ToString());
                        }
                        else
                        {
                            errorSet.Add(DataCompilerError.CompilingLogWithWarning,
                                RawDataName.CharTable, error.ToString());
                        }
                    }

                    errorSet.Merge(CharTableCompiler.Compile(charTable, phoneSet, outputStream));
                }
            }
            catch (XmlException e)
            {
                errorSet.Add(DataCompilerError.RawDataError, e.Message);
            }

            return errorSet;
        }
        public ErrorSet Build(string moduleDataName, Stream outputStream, bool isEnableValidate, string formatGuid)
        {
            ////#region Check arguments
            if (string.IsNullOrEmpty(moduleDataName))
            {
                throw new ArgumentNullException("dataName");
            }

            if (outputStream == null)
            {
                throw new ArgumentNullException("outputStream");
            }
            ////#endregion

            ErrorSet errorSet = new ErrorSet();
            ErrorSet subErrorSet = new ErrorSet();
            try
            {
                switch (moduleDataName)
                {
                    case ModuleDataName.PhoneSet:
                        TtsPhoneSet phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, errorSet);
                        if (!errorSet.Contains(ErrorSeverity.MustFix))
                        {
                            errorSet.Merge(PhoneSetCompiler.Compile(phoneSet, outputStream));
                        }

                        break;

                    case ModuleDataName.BackendPhoneSet:
                        phoneSet = (TtsPhoneSet)GetObject(RawDataName.BackendPhoneSet, errorSet);
                        if (!errorSet.Contains(ErrorSeverity.MustFix))
                        {
                            errorSet.Merge(PhoneSetCompiler.Compile(phoneSet, outputStream));
                        }

                        break;

                    case ModuleDataName.PosSet:
                        TtsPosSet posSet = (TtsPosSet)GetObject(RawDataName.PosSet, errorSet);
                        if (!errorSet.Contains(ErrorSeverity.MustFix))
                        {
                            errorSet.Merge(PosSetCompiler.Compile(posSet, outputStream));
                        }

                        break;

                    case ModuleDataName.PosTaggerPos:
                        LexicalAttributeSchema schema = (LexicalAttributeSchema)GetObject(
                            RawDataName.LexicalAttributeSchema, subErrorSet);
                        MergeDependencyError(errorSet, subErrorSet, _schemaFullName);
                        if (!subErrorSet.Contains(ErrorSeverity.MustFix))
                        {
                            TtsPosSet postaggingPosSet = TtsPosSet.LoadPosTaggingPosFromSchema(schema);
                            errorSet.Merge(PosSetCompiler.CompilePosTaggerPos(postaggingPosSet, outputStream));
                        }

                        break;

                    case ModuleDataName.Lexicon:
                        errorSet = CompileLexicon(outputStream);
                        break;

                    case ModuleDataName.CharTable:
                        ErrorSet charTableErrorSet = CompileCharTable(outputStream);
                        if (!isEnableValidate)
                        {
                            foreach (Error error in charTableErrorSet.Errors)
                            {
                                error.Severity = ErrorSeverity.Warning;
                            }
                        }

                        errorSet.Merge(charTableErrorSet);
                        break;

                    case ModuleDataName.SentenceSeparator:
                        string sentSepDataDir = _dataHandlerList.Datas[RawDataName.SentenceSeparatorDataPath].Path;
                        Collection<string> compiledSentenceSeparatorFiles = new Collection<string>();
                        errorSet = SentenceSeparatorCompiler.Compile(sentSepDataDir, outputStream, compiledSentenceSeparatorFiles);
                        if (errorSet.GetSeverityCount(ErrorSeverity.MustFix) == 0 &&
                            compiledSentenceSeparatorFiles.Count > 0)
                        {
                            errorSet.Add(ReportCompiledFiles("sentence separator", compiledSentenceSeparatorFiles));
                        }

                        break;

                    case ModuleDataName.WordBreaker:
                        {
                            System.IO.MemoryStream memStream = new MemoryStream();
                            string wordBreakerDataDir = _dataHandlerList.Datas[RawDataName.WordBreakerDataPath].Path;
                            Collection<string> compiledWordBreakerFiles = new Collection<string>();
                            errorSet = WordBreakerCompiler.Compile(wordBreakerDataDir, outputStream, compiledWordBreakerFiles, formatGuid);
                            if (errorSet.GetSeverityCount(ErrorSeverity.MustFix) == 0 && compiledWordBreakerFiles.Count > 0)
                            {
                                errorSet.Add(ReportCompiledFiles("word breaker", compiledWordBreakerFiles));
                            }
                        }

                        break;

                    case ModuleDataName.PostWordBreaker:
                        string postWordBreakerFilePath = _dataHandlerList.Datas[RawDataName.PostWordBreaker].Path;
                        errorSet = PostWordBreakerCompiler.Compile(postWordBreakerFilePath, outputStream);
                        break;

                    case ModuleDataName.ChineseTone:
                        string chineseToneFilePath = _dataHandlerList.Datas[RawDataName.ChineseTone].Path;
                        errorSet = ChineseToneCompiler.Compile(chineseToneFilePath, outputStream);
                        break;

                    case ModuleDataName.AcronymDisambiguation:
                        {
                            string acronymDisambiguationDataDir = _dataHandlerList.Datas[RawDataName.AcronymDisambiguation].Path;
                            Collection<string> compiledFiles = new Collection<string>();

                            errorSet = CrfModelCompiler.Compile(acronymDisambiguationDataDir, outputStream, compiledFiles, _language);
                            if (errorSet.GetSeverityCount(ErrorSeverity.MustFix) == 0 &&
                                compiledFiles.Count > 0)
                            {
                                errorSet.Add(ReportCompiledFiles("AcronymDisambiguation", compiledFiles));
                            }
                        }

                        break;

                    case ModuleDataName.NEDisambiguation:
                        {
                            string strNeDisambiguationDataDir = _dataHandlerList.Datas[RawDataName.NEDisambiguation].Path;
                            Collection<string> compiledFiles = new Collection<string>();
                            errorSet = CrfModelCompiler.Compile(strNeDisambiguationDataDir, outputStream, compiledFiles, _language);
                            if (errorSet.GetSeverityCount(ErrorSeverity.MustFix) == 0 &&
                                compiledFiles.Count > 0)
                            {
                                errorSet.Add(ReportCompiledFiles("NEDisambiguation", compiledFiles));
                            }
                        }

                        break;

                    case ModuleDataName.SyllabifyRule:
                        string syllabifyRuleFilePath = _dataHandlerList.Datas[RawDataName.SyllabifyRule].Path;
                        phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, subErrorSet);
                        MergeDependencyError(errorSet, subErrorSet, RawDataName.PhoneSet);
                        if (!subErrorSet.Contains(ErrorSeverity.MustFix))
                        {
                            errorSet.Merge(SyllabifyRuleCompiler.Compile(syllabifyRuleFilePath,
                                phoneSet, outputStream));
                        }

                        break;

                    case ModuleDataName.UnitGenerator:
                        string truncRuleFilePath = _dataHandlerList.Datas[RawDataName.TruncateRule].Path;
                        phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, subErrorSet);
                        MergeDependencyError(errorSet, subErrorSet, RawDataName.PhoneSet);
                        if (!subErrorSet.Contains(ErrorSeverity.MustFix))
                        {
                            errorSet.Merge(UnitGeneratorDataCompiler.Compile(truncRuleFilePath,
                                phoneSet, outputStream));
                        }

                        break;

                    case ModuleDataName.PolyphoneRule:
                        string generalRuleFilePath = _dataHandlerList.Datas[RawDataName.PolyphoneRule].Path;
                        phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, errorSet);
                        PolyphonyRuleFile polyRuleFile = new PolyphonyRuleFile();
                        ErrorSet polyErrorSet = polyRuleFile.Load(generalRuleFilePath, phoneSet);
                        if (!isEnableValidate)
                        {
                            foreach (Error error in polyErrorSet.Errors)
                            {
                                error.Severity = ErrorSeverity.Warning;
                            }
                        }

                        errorSet.Merge(polyErrorSet);
                        errorSet.Merge(CompileGeneralRule(generalRuleFilePath, outputStream));
                        break;

                    case ModuleDataName.BoundaryPronChangeRule:
                        generalRuleFilePath = _dataHandlerList.Datas[RawDataName.BoundaryPronChangeRule].Path;
                        errorSet = CompileGeneralRule(generalRuleFilePath, outputStream);
                        break;

                    case ModuleDataName.SentenceDetector:
                        generalRuleFilePath = _dataHandlerList.Datas[RawDataName.SentenceDetectRule].Path;
                        RuleFile ruleFile = new RuleFile();
                        List<string> dupKeys = ruleFile.GetDupKeys(generalRuleFilePath);
                        if (dupKeys.Count > 0)
                        {
                            foreach (string key in dupKeys)
                            {
                                errorSet.Add(new Error(DataCompilerError.DuplicateItemKey, key));
                            }
                        }
                        else
                        {
                            errorSet = CompileGeneralRule(generalRuleFilePath, outputStream);
                        }

                        break;

                    case ModuleDataName.QuotationMarkTable:
                        QuotationMarkTable quoteTable = QuotationMarkTable.Read(_dataHandlerList.Datas[RawDataName.QuotationMarkTable].Path);
                        errorSet = QuotationMarkCompiler.Compile(quoteTable, outputStream);
                        break;

                    case ModuleDataName.ParallelStructTable:
                        schema = (LexicalAttributeSchema)GetObject(
                            RawDataName.LexicalAttributeSchema, subErrorSet);
                        MergeDependencyError(errorSet, subErrorSet, _schemaFullName);
                        if (!subErrorSet.Contains(ErrorSeverity.MustFix))
                        {
                            TtsPosSet postaggingPosSet = TtsPosSet.LoadPosTaggingPosFromSchema(schema);

                            ParallelStructTable parallelStructTable = ParallelStructTable.Read(_dataHandlerList.Datas[RawDataName.ParallelStructTable].Path);
                            if (postaggingPosSet != null)
                            {
                                errorSet = ParallelStructCompiler.Compile(parallelStructTable, postaggingPosSet, outputStream);
                            }
                        }

                        break;

                    case ModuleDataName.WordFeatureSuffixTable:
                        schema = (LexicalAttributeSchema)GetObject(
                            RawDataName.LexicalAttributeSchema, subErrorSet);
                        MergeDependencyError(errorSet, subErrorSet, _schemaFullName);
                        if (!subErrorSet.Contains(ErrorSeverity.MustFix))
                        {
                            WordFeatureSuffixTable suffixTable = WordFeatureSuffixTable.Read(_dataHandlerList.Datas[RawDataName.WordFeatureSuffixTable].Path);
                            errorSet = WordFeatureSuffixCompiler.Compile(suffixTable, outputStream);
                        }

                        break;

                    case ModuleDataName.LtsRule:
                        string ltsRuleDataPath = _dataHandlerList.Datas[RawDataName.LtsRuleDataPath].Path;
                        errorSet = CompileLtsRule(ltsRuleDataPath, outputStream);
                        break;

                    case ModuleDataName.PhoneEventData:
                         PhoneConverterWrapper pcw = null;

                        // Check if the language has phone mapping data.
                        if (_moduleDataSet.ContainsKey(ModuleDataName.PhoneMappingRule))
                        {
                            // Check phone mapping binary data dependency.
                            if (_moduleDataSet[ModuleDataName.PhoneMappingRule].Data != null)
                            {
                                pcw = new PhoneConverterWrapper(_language, _moduleDataSet[ModuleDataName.PhoneMappingRule].Data);
                            }
                            else
                            {
                                errorSet.Add(DataCompilerError.DependenciesNotValid, "Please make sure that PhoneMappingRule has been compiled before PhoneEvent");
                            }
                        }

                        if (errorSet.GetSeverityCount(ErrorSeverity.MustFix) == 0)
                        {
                            phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, errorSet);
                            errorSet = PhoneEventCompiler.Compile(phoneSet, pcw, outputStream);
                        }

                        break;

                    case ModuleDataName.PosRule:
                        string lexicalRuleFilePath = _dataHandlerList.Datas[RawDataName.PosLexicalRule].Path;
                        string contextualRuleFilePath = _dataHandlerList.Datas[RawDataName.PosContextualRule].Path;
                        schema = (LexicalAttributeSchema)GetObject(
                            RawDataName.LexicalAttributeSchema, subErrorSet);
                        MergeDependencyError(errorSet, subErrorSet, _schemaFullName);
                        if (!subErrorSet.Contains(ErrorSeverity.MustFix))
                        {
                            posSet = TtsPosSet.LoadPosTaggingPosFromSchema(schema);
                            string posSetFilePath = Helper.GetTempFileName();
                            posSet.Save(posSetFilePath, Encoding.Unicode);
                            errorSet.Merge(CompilePosRule(lexicalRuleFilePath, contextualRuleFilePath,
                                posSetFilePath, outputStream));
                            File.Delete(posSetFilePath);
                        }

                        break;

                    case ModuleDataName.TnRule:
                        {
                            string tnmlRuleFilePath = _dataHandlerList.Datas[moduleDataName].Path;
                            string schemaFilePath = _dataHandlerList.Datas[RawDataName.LexicalAttributeSchema].Path;
                            errorSet = CompileTnml(tnmlRuleFilePath, schemaFilePath, outputStream, true);
                        }

                        break;

                    case ModuleDataName.FstNERule:
                        {
                            string fstNERuleFilePath = _dataHandlerList.Datas[moduleDataName].Path;
                            errorSet = CompileFstNE(fstNERuleFilePath, outputStream);
                        }

                        break;

                    case ModuleDataName.CompoundRule:
                        {
                            string tnmlRuleFilePath = _dataHandlerList.Datas[moduleDataName].Path;
                            string schemaFilePath = _dataHandlerList.Datas[RawDataName.LexicalAttributeSchema].Path;
                            phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, errorSet);
                            ErrorSet compundRuleError = DataFileValidator.ValidateCompoundRule(
                                    _dataHandlerList.Datas[moduleDataName].Path, phoneSet);

                            if (!isEnableValidate)
                            {
                                foreach (Error error in compundRuleError.Errors)
                                {
                                    error.Severity = ErrorSeverity.Warning;
                                }
                            }

                            errorSet.Merge(compundRuleError);
                            errorSet.Merge(CompileTnml(tnmlRuleFilePath, schemaFilePath, outputStream, false));
                        }

                        break;
                    case ModuleDataName.PhoneMappingRule:
                    case ModuleDataName.BackendPhoneMappingRule:
                    case ModuleDataName.FrontendBackendPhoneMappingRule:
                    case ModuleDataName.MixLingualPOSConverterData:
                        {
                            string tnmlRuleFilePath = _dataHandlerList.Datas[moduleDataName].Path;
                            string schemaFilePath = _dataHandlerList.Datas[RawDataName.LexicalAttributeSchema].Path;
                            errorSet = CompileTnml(tnmlRuleFilePath, schemaFilePath, outputStream, false);
                        }

                        break;
                    case ModuleDataName.ForeignLtsCollection:
                        errorSet = CompileForeignLtsCollection(_dataHandlerList.Datas[moduleDataName].Path, outputStream);
                        break;
                    case ModuleDataName.PolyphonyModel:
                        {
                            string polyphonyModelDataDir = _dataHandlerList.Datas[RawDataName.PolyphonyModel].Path;
                            Collection<string> compiledFiles = new Collection<string>();
                            errorSet = CrfModelCompiler.Compile(polyphonyModelDataDir, outputStream, compiledFiles, _language);
                            if (errorSet.GetSeverityCount(ErrorSeverity.MustFix) == 0 &&
                                compiledFiles.Count > 0)
                            {
                                errorSet.Add(ReportCompiledFiles("PolyphonyModel", compiledFiles));
                            }
                        }

                        break;
                    case ModuleDataName.RNNPolyphonyModel:
                        {
                            string polyphonyModelDataPath = _dataHandlerList.Datas[RawDataName.RNNPolyphonyModel].Path;
                            Collection<string> compiledFiles = new Collection<string>();
                            errorSet = RNNModelCompiler.Compile(polyphonyModelDataPath, outputStream, compiledFiles);
                            if (errorSet.GetSeverityCount(ErrorSeverity.MustFix) == 0 &&
                                compiledFiles.Count > 0)
                            {
                                errorSet.Add(ReportCompiledFiles("PolyphonyModel", compiledFiles));
                            }
                        }

                        break;
                    default:
                        errorSet.Add(DataCompilerError.InvalidModuleData, moduleDataName);
                        break;
                }
            }
            catch (Exception ex)
            {
                Type exceptionType = ex.GetType();
                if (exceptionType.Equals(typeof(FileNotFoundException)) ||
                    exceptionType.Equals(typeof(ArgumentNullException)) ||
                    exceptionType.Equals(typeof(XmlException)) ||
                    exceptionType.Equals(typeof(InvalidDataException)))
                {
                    errorSet.Add(DataCompilerError.RawDataNotFound, moduleDataName,
                        Helper.BuildExceptionMessage(ex));
                }
                else
                {
                    throw;
                }
            }

            return errorSet;
        }
        /// <summary>
        /// Handle the command line and generate the output.
        /// </summary>
        /// <param name="lexicalRuleFilePath">Path of POS Lexical rule.</param>
        /// <param name="contextualRuleFilePath">Path of POS Contectual Rule.</param>
        /// <param name="posSetFilePath">Path of POS set.</param>
        /// <param name="outputStream">Output stream.</param>
        /// <returns>ErrorSet.</returns>
        private ErrorSet CompilePosRule(string lexicalRuleFilePath, string contextualRuleFilePath,
            string posSetFilePath, Stream outputStream)
        {
            ErrorSet errorSet = new ErrorSet();
            string toolFileName = ToolName.PosRuleCompiler;
            string binaryPosRulePath = Helper.GetTempFileName();
            string compilingArguments = Helper.NeutralFormat("\"{0}\" \"{1}\" \"{2}\" \"{3}\"",
                lexicalRuleFilePath, contextualRuleFilePath, posSetFilePath, binaryPosRulePath);
            string toolPath = Path.Combine(ToolDir, toolFileName);

            CheckToolExists(toolPath, errorSet);
            if (!File.Exists(lexicalRuleFilePath))
            {
                errorSet.Add(DataCompilerError.RawDataNotFound, RawDataName.PosLexicalRule, lexicalRuleFilePath);
            }
            
            if (!File.Exists(contextualRuleFilePath))
            {
                errorSet.Add(DataCompilerError.RawDataNotFound, RawDataName.PosContextualRule, contextualRuleFilePath);
            }
            
            if (!File.Exists(posSetFilePath))
            {
                errorSet.Add(DataCompilerError.RawDataNotFound, RawDataName.PosSet, posSetFilePath);
            }

            if (!errorSet.Contains(ErrorSeverity.MustFix))
            {
                HandleCommandLine(ModuleDataName.PosRule, toolPath, compilingArguments,
                    binaryPosRulePath, outputStream, errorSet);
            }

            return errorSet;
        }
        /// <summary>
        /// General Rule Compiler.
        /// </summary>
        /// <param name="txtPath">Path of txt formatted general rule.</param>
        /// <param name="outputStream">Output stream.</param>
        /// <returns>ErrorSet.</returns>
        private ErrorSet CompileGeneralRule(string txtPath, Stream outputStream)
        {
            ErrorSet errorSet = new ErrorSet();
            string toolFileName = ToolName.RuleCompiler;
            string binaryRulePath = Helper.GetTempFileName();
            string compilingArguments = Helper.NeutralFormat("\"{0}\" \"{1}\"", txtPath, binaryRulePath);
            string toolPath = Path.Combine(ToolDir, toolFileName);
            const string DataName = "General Rule";
            CheckToolExists(toolPath, errorSet);
            
            if (!File.Exists(txtPath))
            {
                errorSet.Add(DataCompilerError.RawDataNotFound, DataName, txtPath);
            }
            
            if (!errorSet.Contains(ErrorSeverity.MustFix))
            {
                HandleCommandLine(DataName, toolPath, compilingArguments,
                    binaryRulePath, outputStream, errorSet);
            }

            return errorSet;
        }
        /// <summary>
        /// FstNE rule compiler.
        /// </summary>
        /// <param name="fstNERuleFilePath">Path of FstNE rule.</param>
        /// <param name="outputStream">Output stream.</param>
        /// <returns>ErrorSet.</returns>
        private ErrorSet CompileFstNE(string fstNERuleFilePath, Stream outputStream)
        {
            ErrorSet errorSet = new ErrorSet();
            string toolFileName = ToolName.FstNECompiler;
            string binaryFstNERulePath = Helper.GetTempFileName();

            string compilingArguments = Helper.NeutralFormat(
                "-lang {0} -intnml \"{1}\" -outfst \"{2}\"",
                Localor.LanguageToString(_language), fstNERuleFilePath, binaryFstNERulePath);

            string toolPath = Path.Combine(ToolDir, toolFileName);

            CheckToolExists(toolPath, errorSet);
            if (!File.Exists(fstNERuleFilePath))
            {
                errorSet.Add(DataCompilerError.RawDataNotFound, "FstNE rule", fstNERuleFilePath);
            }

            if (!errorSet.Contains(ErrorSeverity.MustFix))
            {
                HandleCommandLine("FstNE rule", toolPath, compilingArguments,
                    binaryFstNERulePath, outputStream, errorSet);
            }

            return errorSet;
        }
        /// <summary>
        /// Tnml rule compiler.
        /// </summary>
        /// <param name="tnmlRuleFilePath">Path of Tnml rule.</param>
        /// <param name="schemaFilePath">Path of Lexical Attribute Schema.</param>
        /// <param name="outputStream">Output stream.</param>
        /// <param name="isTNRule">Whether it's TN rule.</param>
        /// <returns>ErrorSet.</returns>
        private ErrorSet CompileTnml(string tnmlRuleFilePath, string schemaFilePath, Stream outputStream, bool isTNRule)
        {
            ErrorSet errorSet = new ErrorSet();
            string toolFileName = ToolName.TnmlCompiler;
            string binaryTnmlRulePath = Helper.GetTempFileName();
            string compilingArguments = Helper.NeutralFormat(
                "-lcid {0} -tnml \"{1}\" -schema \"{2}\" -tnbin \"{3}\"",
                (uint)_language, tnmlRuleFilePath, schemaFilePath, binaryTnmlRulePath);
            if (isTNRule)
            {
                compilingArguments += " -mode TTS -norulename FALSE";
            }

            string toolPath = Path.Combine(ToolDir, toolFileName);

            CheckToolExists(toolPath, errorSet);
            if (!File.Exists(tnmlRuleFilePath))
            {
                errorSet.Add(DataCompilerError.RawDataNotFound, "TNML rule", tnmlRuleFilePath);
            }

            if (!File.Exists(schemaFilePath))
            {
                errorSet.Add(DataCompilerError.RawDataNotFound, RawDataName.LexicalAttributeSchema, schemaFilePath);
            }

            if (!errorSet.Contains(ErrorSeverity.MustFix))
            {
                HandleCommandLine("TNML rule", toolPath, compilingArguments,
                    binaryTnmlRulePath, outputStream, errorSet);
            }

            return errorSet;
        }
        /// <summary>
        /// Compile LTS rule.
        /// </summary>
        /// <param name="ltsDataDir">Directory of LTS data.</param>
        /// <param name="outputStream">Output stream.</param>
        /// <returns>Error Set.</returns>
        private ErrorSet CompileLtsRule(string ltsDataDir, Stream outputStream)
        {
            ErrorSet errorSet = new ErrorSet();
            string toolFileName = ToolName.LtsCompiler;
            string letterSymPath = Path.Combine(ltsDataDir, "letter.sym");
            string phoneSymPath = Path.Combine(ltsDataDir, "phone.sym");
            string letterQPath = Path.Combine(ltsDataDir, "letter.q");
            string phoneQPath = Path.Combine(ltsDataDir, "phone.q");
            string ltsTreePath = Path.Combine(ltsDataDir, "tree.tree");
            string trainSmpPath = Path.Combine(ltsDataDir, "train.smp");
            CheckRawDataExists(letterSymPath, errorSet);
            CheckRawDataExists(phoneSymPath, errorSet);
            CheckRawDataExists(letterQPath, errorSet);
            CheckRawDataExists(phoneQPath, errorSet);
            CheckRawDataExists(ltsTreePath, errorSet);
            CheckRawDataExists(trainSmpPath, errorSet);

            string binaryLtsPath = Helper.GetTempFileName();
            string compilingArguments = Helper.NeutralFormat(
                "\"{0}\" \"{1}\" \"{2}\" \"{3}\" \"{4}\" {5} {6} {7} \"{8}\" \"{9}\"",
                letterSymPath, phoneSymPath, letterQPath, phoneQPath, ltsTreePath,
                0, 0, 0.00000001,
                trainSmpPath, binaryLtsPath);
            string toolPath = Path.Combine(ToolDir, toolFileName);
            CheckToolExists(toolPath, errorSet);

            if (!errorSet.Contains(ErrorSeverity.MustFix))
            {
                HandleCommandLine(ModuleDataName.LtsRule, toolPath, compilingArguments,
                    binaryLtsPath, outputStream, errorSet);
            }

            return errorSet;
        }
        private ErrorSet CompileLexicon(Stream outputStream)
        {
            if (outputStream == null)
            {
                throw new ArgumentNullException("outputStream");
            }

            ErrorSet errorSet = new ErrorSet();

            ErrorSet subErrorSet = new ErrorSet();
            LexicalAttributeSchema schema = (LexicalAttributeSchema)GetObject(
                RawDataName.LexicalAttributeSchema, subErrorSet);
            MergeDependencyError(errorSet, subErrorSet, _schemaFullName);

            subErrorSet.Clear();
            TtsPhoneSet phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, subErrorSet);
            MergeDependencyError(errorSet, subErrorSet, RawDataName.PhoneSet);

            if (!errorSet.Contains(ErrorSeverity.MustFix))
            {
                Microsoft.Tts.Offline.Core.Lexicon lexicon = (Microsoft.Tts.Offline.Core.Lexicon)GetObject(RawDataName.Lexicon, errorSet);
                errorSet.Merge(lexicon.ErrorSet);

                // Change to case insensitive lexicon
                MemoryStream lexiconStream = new MemoryStream();
                using (XmlWriter xmlWriter = XmlWriter.Create(lexiconStream))
                {
                    Microsoft.Tts.Offline.Core.Lexicon.ContentControler lexiconControler = 
                        new Microsoft.Tts.Offline.Core.Lexicon.ContentControler();
                    lexiconControler.IsCaseSensitive = true;
                    lexicon.Save(xmlWriter, lexiconControler);
                }

                lexiconStream.Seek(0, SeekOrigin.Begin);
                Microsoft.Tts.Offline.Core.Lexicon caseInsensitiveLexicon = new Microsoft.Tts.Offline.Core.Lexicon();
                using (StreamReader sr = new StreamReader(lexiconStream))
                {
                    caseInsensitiveLexicon.Load(sr);
                }

                if (caseInsensitiveLexicon != null && !errorSet.Contains(ErrorSeverity.MustFix))
                {
                    caseInsensitiveLexicon.LexicalAttributeSchema = schema;

                    caseInsensitiveLexicon.PhoneSet = phoneSet;
                    caseInsensitiveLexicon.Validate();

                    // Set severity of errors only in case-insensitive lexicon to NoError for they're not treated as real error
                    caseInsensitiveLexicon.ErrorSet.SetSeverity(ErrorSeverity.NoError);

                    string vendorLexiconPath = Helper.GetTempFileName();

                    caseInsensitiveLexicon.SaveToVendorLexicon(vendorLexiconPath);

                    string toolFileName = ToolName.BldVendor2;
                    string binaryLexiconPath = Helper.GetTempFileName();

                    string compilingArguments = Helper.NeutralFormat("-v {0} V2 \"{1}\" \"{2}\" \"{3}\" TTS",
                        (int)_language, _dataHandlerList.Datas[RawDataName.LexicalAttributeSchema].Path,
                        vendorLexiconPath, binaryLexiconPath);
                    string toolPath = Path.Combine(ToolDir, toolFileName);

                    CheckToolExists(toolPath, errorSet);
                    if (!errorSet.Contains(ErrorSeverity.MustFix))
                    {
                        HandleCommandLine(ModuleDataName.Lexicon, toolPath, compilingArguments,
                            binaryLexiconPath, outputStream, errorSet);
                    }

                    File.Delete(vendorLexiconPath);

                    errorSet.Merge(caseInsensitiveLexicon.ErrorSet);
                }
                else if (lexicon == null)
                {
                    errorSet.Add(DataCompilerError.RawDataError, "Lexicon");
                }
                else
                {
                    errorSet.Merge(caseInsensitiveLexicon.ErrorSet);
                }
            }

            return errorSet;
        }
        /// <summary>
        /// Compile the foreign LTS collection.
        /// </summary>
        /// <param name="configuration">Foreign LTS configuration.</param>
        /// <param name="outputStream">Output steam.</param>
        /// <returns>Error set.</returns>
        private ErrorSet CompileForeignLtsCollection(string configuration, Stream outputStream)
        {
            ErrorSet errorSet = new ErrorSet();

            // The configuration is written in
            // "originLanguageA : phonesetA ; RuleA ; originLanguageB: phonesetB ; RuleB"
            string[] phonesetLtsList = configuration.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            ushort count = Convert.ToUInt16(phonesetLtsList.Length / 2);
            Offline.Language[] languages = new Offline.Language[count];
            TtsPhoneSet[] phoneSets = new TtsPhoneSet[count];
            string[] ltsPaths = new string[count];

            // Load the phone sets
            for (ushort i = 0; i < count; i++)
            {
                languages[i] = Offline.Language.Neutral;
                string phoneSetPath = phonesetLtsList[i * 2].Trim();
                int languageSeparatorIndex = phoneSetPath.IndexOf(":");
                if (languageSeparatorIndex != -1)
                {
                    string language = phoneSetPath.Substring(0, languageSeparatorIndex).Trim();
                    languages[i] = Localor.StringToLanguage(language);
                    phoneSetPath = phoneSetPath.Substring(languageSeparatorIndex + 1, phoneSetPath.Length - languageSeparatorIndex - 1).Trim();
                }

                if (!Path.IsPathRooted(phoneSetPath))
                {
                    phoneSetPath = Path.Combine(_dataHandlerList.DataRoot, phoneSetPath);
                }

                phoneSets[i] = new TtsPhoneSet();
                phoneSets[i].Load(phoneSetPath);
                phoneSets[i].Validate();
                if (languages[i] == Offline.Language.Neutral)
                {
                    languages[i] = phoneSets[i].Language;
                }

                errorSet.Merge(phoneSets[i].ErrorSet);
                if (phoneSets[i].ErrorSet.Contains(ErrorSeverity.MustFix))
                {
                    phoneSets[i] = null;
                }
                else
                {
                    ltsPaths[i] = phonesetLtsList[(i * 2) + 1].Trim();
                    if (!Path.IsPathRooted(ltsPaths[i]))
                    {
                        ltsPaths[i] = Path.Combine(_dataHandlerList.DataRoot, ltsPaths[i]);
                    }
                }
            }

            if (!errorSet.Contains(ErrorSeverity.MustFix))
            {
                BinaryWriter bw = new BinaryWriter(outputStream);
                {
                    bw.Write((ushort)count);
                    for (ushort i = 0; i < count; i++)
                    {
                        bw.Write((ushort)languages[i]);
                        bw.Write((ushort)phoneSets[i].Language);
                    }

                    // Write phone set offset
                    long phoneSetOffset = bw.BaseStream.Position;
                    for (byte i = 0; i < count; i++)
                    {
                        bw.Write((uint)0);
                    }

                    // Write LTS offset
                    long ltsOffset = bw.BaseStream.Position;
                    for (byte i = 0; i < count; i++)
                    {
                        bw.Write((uint)0);
                    }

                    // Write phone set
                    for (byte i = 0; i < count; i++)
                    {
                        long offset = bw.BaseStream.Position;
                        bw.BaseStream.Seek(phoneSetOffset, SeekOrigin.Begin);
                        if (offset > uint.MaxValue)
                        {
                            throw new InvalidDataException(Helper.NeutralFormat(
                                "Foreign LTS collection size exceeds the maximal size {0}", uint.MaxValue));
                        }

                        bw.Write((uint)offset);
                        phoneSetOffset += sizeof(uint);
                        bw.BaseStream.Seek(offset, SeekOrigin.Begin);
                        errorSet.Merge(PhoneSetCompiler.Compile(phoneSets[i], bw.BaseStream));
                    }

                    // Write LTS
                    for (byte i = 0; i < count; i++)
                    {
                        long offset = bw.BaseStream.Position;
                        bw.BaseStream.Seek(ltsOffset, SeekOrigin.Begin);
                        if (offset > uint.MaxValue)
                        {
                            throw new InvalidDataException(Helper.NeutralFormat(
                                "Foreign LTS collection size exceeds the maximal size {0}", uint.MaxValue));
                        }

                        bw.Write((uint)offset);
                        ltsOffset += sizeof(uint);
                        bw.BaseStream.Seek(offset, SeekOrigin.Begin);
                        LoadStream(ltsPaths[i], bw.BaseStream);
                    }
                }
            }

            return errorSet;
        }