/// <summary> /// Takes the given readers which begins on or before the name of the first child and parses children /// until it its ParseChildren attempt finds its own '}' /// </summary> /// <param name="reader"></param> /// <param name="node"></param> private static void ParseChildren(TextReader reader, IcuDataNode node) { IcuDataNode childNode; // Keep parsing children until one of them finds our end '}' while(Parse(reader,out childNode,node)==false) { if(childNode != null) { node.AddChildSimple(childNode); } } }
/// <summary> /// Parses a file returning the root node. /// If there is more than one root node in the file. /// these nodes will be treated as white space or comments. /// </summary> /// <param name="reader">The file to be read.</param> /// <param name="rootNode">The "root" node of the file. (not neccessarily named "root")</param> /// <returns></returns> public static void Parse(TextReader reader, out IcuDataNode rootNode) { Parse(reader,out rootNode,null); rootNode.PostSpace += reader.ReadToEnd(); }
/// <summary> /// Finds one new node and its chilren. /// /// (If it find attributes instead of a new node, it will add the attributes to the <c>parent</c>) /// /// Parses the reader assuming that the first line of the reader will be either comments before the /// first line of the node, or the first line of the node itself. /// /// This will read either to the closing '}' of the parent who called it, and return <c>true</c> /// or it will read to the last line of itself, and return <c>false</c> /// </summary> /// <remarks> /// </remarks> /// <param name="writer">The reader to parse from.</param> /// <param name="node">The new node, will be null if there was no data given.</param> /// <param name="parent">The parent, used to add data if this wasn't really a new node. /// parent may be null.</param> /// <returns><code>true</code> if we have parsed the ending '}' for the parent node.</returns> public static bool Parse( TextReader reader, out IcuDataNode newNode, IcuDataNode parent) { newNode = null; string firstWhitespace = ""; string secondWhitespace = ""; string firstToken = ""; string secondToken = ""; // 1. Find name of a new child node of the parent // e.g. "name { [ // comment ]" not " // comment { comment // (or an attribute of parent) while(true) { // Parse a single whitespace and token ParseToken( reader, out firstWhitespace, out firstToken ); // if we find the end of the parent return "true" if( firstToken == "}" ) { // If it is an empty node, add the comments as braceSpace if( parent.children.Count < 1 ) { parent.BraceSpace = firstWhitespace; } else { // Add the whitespace after the last brace ((IcuDataNode)parent.children[parent.children.Count-1]).PostSpace += firstWhitespace; } // we found the parent's '}' return true; } // If we find a child node with no name, allow it else if( firstToken == "{" ) { newNode = new IcuDataNode(); newNode.name = ""; newNode.PreSpace = firstWhitespace; ParseChildren(reader,newNode); // we did not find the parent's '}' return false; } // Pares a second whitespace and token ParseToken( reader, out secondWhitespace, out secondToken ); // if we find a new child node if( secondToken == "{" ) { newNode = new IcuDataNode(); newNode.name = firstToken; newNode.PreSpace = firstWhitespace; newNode.AfterNameSpace = secondWhitespace; ParseChildren(reader,newNode); // If we made it to this point, // then we have parsed all the sub-nodes and the last one found our '}' // At this point we have not found our parent's '}' return false; } // We found only one attribute for the parent. else if( secondToken == "}" ) { parent.BraceSpace += firstWhitespace; parent.AddAttribute(firstToken, secondWhitespace, false); // We found the parent's ending '}' return true; } // There are two data elements in a row else { parent.BraceSpace += firstWhitespace; parent.AddAttribute(firstToken,secondWhitespace, false); string lastToken = secondToken; string currentToken; // Add children until we find the "}" while( lastToken != "}" ) { ParseToken( reader, out firstWhitespace, out currentToken); parent.AddAttribute( lastToken, firstWhitespace, false ); lastToken = currentToken; } // found the end of the parent return true; } } }
/// <summary> /// Adds the given child, overwriting the first existing child with the same name, if there is one. /// Properly handles the indenting in the "space" member variables. /// </summary> /// <param name="child">The child to add.</param> /// <param name="addAtTop">Should the child be added before the rest.</param> public void AddChildSmart(IcuDataNode newChild, bool addAtTop) { if( children.Count == 0 ) { AddChildSimple(newChild); // Add a new line so that this nodes '}' will be on it's own line newChild.PostSpace += Environment.NewLine; return; } for(int index=0; index < children.Count; index++) { if( ((IcuDataNode)children[index]).name == newChild.name ) { // overwrite the existing child newChild.parent = this; // If this is the last child we need to move the new line from the old last child to this new one. if( index == children.Count - 1) { // Move the newline from the post comment of the last child to the new last child ((IcuDataNode)children[children.Count-1]).PostSpace = RemoveNewlineFromEnd(((IcuDataNode)children[children.Count-1]).PostSpace); newChild.PostSpace += Environment.NewLine; } children[index]=newChild; return; } } if( addAtTop ) // Add the child at the beginning AddChildSimple(newChild,true); else { // Move the newline from the post comment of the last child to the new last child ((IcuDataNode)children[children.Count-1]).PostSpace = RemoveNewlineFromEnd(((IcuDataNode)children[children.Count-1]).PostSpace); newChild.PostSpace += Environment.NewLine; // Add the child at the end AddChildSimple(newChild); } }
/// <summary> /// Creates a new IcuDataNode with no attributes or children. /// /// All comments should not be indented and should not end with a newline. /// </summary> /// <param name="name">The name of this new node.</param> /// <param name="parent">The parent this will be a child of, for indent information.</param> /// <param name="preComment">The comment that appears before this node.</param> /// <param name="newline">Whether the node should appear on more than one line.</param> /// <param name="postComment">The comment that appears after the node.</param> public IcuDataNode(string name, IcuDataNode parent, string preComment, string postComment) { // Set the name this.name = name; // Adds a space after the name this.AfterNameSpace = " "; // The node must put itself on a new line. this.PreSpace = Environment.NewLine; // Add the comments on new lines, if there are comments if( preComment != "") this.PreSpace += preComment + Environment.NewLine; if( postComment != "") this.PostSpace = Environment.NewLine + postComment; }
/// <summary> /// Adds the given child at the end. /// (with no adjustment of spacing or overwriting of existing nodes.) /// </summary> /// <param name="child"></param> public void AddChildSimple(IcuDataNode newChild) { AddChildSimple(newChild, false); }
/// <summary> /// Adds the child at the beginning or end with no overwriting of existing nodes or adjusment of spacing. /// </summary> /// <param name="newChild"></param> /// <param name="addAtTop"><c>true</c> if the child should be added before the rest.</param> public void AddChildSimple(IcuDataNode newChild, bool addAtTop) { // Indent the child one more than this; if( this.indentCount != UNDEFINED_INDENT ) newChild.indentCount = (short)(this.indentCount + 1); newChild.parent = this; if( addAtTop ) { children.Insert(0,newChild); } else { children.Add(newChild); } }
public static bool RemoveICUDataFileChild(IcuDataNode rootNode, NodeSpecification nodeSpec, string childName) { IcuDataNode specifiedNode = nodeSpec.FindNode(rootNode,false); if( specifiedNode == null ) return false; return specifiedNode.removeChild(childName); }
/// <summary> /// Find the specified node in the given root. /// </summary> /// <param name="root">The root node to search, must match the first word in the specification.</param> /// <param name="mustExist"> /// If this is <c>true</c>, /// then throw an exception if the path doesn't specify and existing node. /// If this is <c>false</c>, /// the IcuDataNode returned will be <c>null</c> if none is found.</param> /// <returns></returns> public IcuDataNode FindNode( IcuDataNode root, bool mustExist) { // The root node's name must match the given root node. if( root.Name != nodePath[0] ) { if( mustExist == true ) { LogFile.AddErrorLine("Error finding node: root name does not match requested name"); throw new InstallLanguage.Errors.LDExceptions( InstallLanguage.Errors.ErrorCodes.ICUNodeAccessError); } else return null; } IcuDataNode currentNode = root; // Find each node in the path, assuming that it is the child of the previous node. for( int index = 1; index < nodePath.Length; index++) { currentNode = currentNode.Child(((string)nodePath[index])); // If the node is not a child as expected throw an exception. if( currentNode == null ) { if( mustExist ) { // Log a detailed description and exit LogFile.AddErrorLine("Error finding node: " + ToString()); LogFile.AddErrorLine("Node does not exists: " + nodePath[index]); throw new InstallLanguage.Errors.LDExceptions( InstallLanguage.Errors.ErrorCodes.ICUNodeAccessError); } else return null; } } return currentNode; }
public static int RemoveICUDataFileAttribute(IcuDataNode rootNode, NodeSpecification nodeSpec, string attributeValue) { IcuDataNode specifiedNode = nodeSpec.FindNode(rootNode,false); if( specifiedNode == null ) return -1; return specifiedNode.removeAttribute(attributeValue); }
/// <summary> /// Finds and sets the childNode, inserting or replacing as necessary. /// </summary> /// <param name="file">The complete file path to open</param> /// <param name="nodeSpec">The path to the node that will have a new child.</param> /// <param name="newChild">The new child to add, replacing existing children as necessary.</param> public static void SetICUDataFileNode(string file, NodeSpecification nodeSpec, IcuDataNode newChild, bool addAtTop) { // Get the node they chose IcuDataNode chosenNode = nodeSpec.FindNode( ParsedFile(file), false ); // Add the child if (chosenNode != null) chosenNode.AddChildSmart(newChild, addAtTop); }
/// <summary> /// Process all changes related to ICU locale and collation files. This updates three /// source text files in icu\data\locales, and possibly two source text files in /// icu\data\coll, then uses these to generate corresponding res files in icu\icudtXXl /// and icu\icudtXXl\coll. Before modifying any of the files, it makes an original /// backup if one doesn't already exist. During the process, it makes backup files so /// that if anything goes wrong during the process, it can restore everything to the /// state prior to making these changes. /// </summary> /// <param name="m_ldData">The parser holding information from the language /// definition file</param> public void InstallLDFile(string ldFilename) { #region Just some test code Base Local Parsers // This method was left here as a location where the parser test could be called // // bool passed = TestBaseLocaleParsers(); // // bool test = true; // if (test) // throw new LDExceptions(ErrorCodes.ProgrammingError); #endregion // Parse the xml file into m_ldData ParseLanguageDataFile(ldFilename); // create the core 6 files: // root.txt, res_index.txt, xx.txt, // icu26ldt_root.res, icu26ldt_res_index.res, icu26ldt_xx.res // string rootTxtInput = m_localeDirectory + "root.txt"; string resIndexTxtInput = m_localeDirectory + "res_index.txt"; string rootResInput = m_icuBase + m_IcuData + "root.res"; string resIndexResInput = m_icuBase + m_IcuData + "res_index.res"; string xxTxtFile = m_localeDirectory + m_ldData.NewLocale + ".txt"; string xxCollTxtFile = m_collDirectory + m_ldData.NewLocale + ".txt"; string xxResFile = m_icuBase + m_IcuData + m_ldData.NewLocale + ".res"; // the root file text has to exist for this process to work - throw exception if (!File.Exists(rootTxtInput)) throw new LDExceptions(ErrorCodes.RootTxt_FileNotFound); // the res index file has to exist for this process to work - throw exception if (!File.Exists(resIndexTxtInput)) throw new LDExceptions(ErrorCodes.ResIndexTxt_FileNotFound); // Determine which ICU locale resources should be updated with the name of the new language. int cwsNames = m_ldData.Names.Count; ICUInfo[] icuInfo = new ICUInfo[cwsNames]; string[] rgXx = new string[cwsNames]; string[] rgXxTxtFiles = new string[cwsNames]; string[] rgXxResFiles = new string[cwsNames]; string icuLocales = ""; // used for output tracing for (int iws = 0; iws < cwsNames; ++iws) { rgXx[iws] = ((StringWithWs)m_ldData.Names[iws]).icuLocale; icuLocales += " " + rgXx[iws]; if (rgXx[iws] == m_ldData.NewLocale) { rgXxTxtFiles[iws] = null; // (probably redundant...) rgXxResFiles[iws] = null; } else { rgXxTxtFiles[iws] = m_localeDirectory + rgXx[iws] + ".txt"; rgXxResFiles[iws] = m_icuBase + m_IcuData + rgXx[iws] + ".res"; // get information for this locale in the icuInfo[iws] = GetIcuResourceInfo(rgXxTxtFiles[iws], m_ldData.NewLocale, rgXx[iws]); } } // DN-271 use the Custom resource that contains all the Locales, Languages, // Countries and Variants that we've added to the root.txt file to see if // this is one of them. CustomResourceInfo newLangInfo = GetCustomResourceInfo(rootTxtInput, m_ldData.NewLocale, rgXx); if (LogFile.IsLogging()) // put out some debugging info { LogFile.AddLine("Locale : <" + newLangInfo.LocaleItems.Locale + ">"); LogFile.AddLine("Language: <" + newLangInfo.LocaleItems.LangKey + ">"); LogFile.AddLine("Script : <" + newLangInfo.LocaleItems.ScriptKey + ">"); LogFile.AddLine("Country : <" + newLangInfo.LocaleItems.CountryKey + ">"); LogFile.AddLine("Variant : <" + newLangInfo.LocaleItems.VariantKey + ">"); string custom = ""; if (newLangInfo.HasLocale) custom += " Locale"; if (newLangInfo.HasLanguage) custom += " Language(" + icuLocales + ")"; if (newLangInfo.HasScript) custom += " Script(" + icuLocales + ")"; if (newLangInfo.HasCountry) custom += " Country(" + icuLocales + ")"; if (newLangInfo.HasVariant) custom += " Variant(" + icuLocales + ")"; if (custom.Length <= 0) custom = " None"; LogFile.AddLine("Components that already exist in the custom resource: " + custom); for (int i = 0; i < cwsNames; i++) { string icu = ""; ICUInfo info = icuInfo[i]; if (info != null) { if (info.HasLanguage) icu += " Language"; if (info.HasScript) icu += " Script"; if (info.HasCountry) icu += " Country"; if (info.HasVariant) icu += " Variant"; } if (icu.Length <= 0) icu = " None"; LogFile.AddLine("Components that already exist in " + rgXx[i] + ".txt: " + icu); } } // DN-246 1. see if it's a factory locale - if so, do Nothing, just return if (newLangInfo.HasLocale == false && (File.Exists(xxTxtFile) || File.Exists(xxCollTxtFile))) { LogFile.AddLine("It's a factory Locale - do nothing"); return; // factory locale } // Check for ICU script and actual locale script key if (newLangInfo.LocaleItems.ScriptKey.Length > 0) { string icuScript, displayScript; Icu.UErrorCode err; StringUtils.InitIcuDataDir(); // initialize ICU data dir Icu.GetScriptCode(newLangInfo.LocaleItems.Locale, out icuScript, out err); if (newLangInfo.LocaleItems.ScriptKey != icuScript) { string script = newLangInfo.LocaleItems.ScriptKey; Icu.GetDisplayScript(newLangInfo.LocaleItems.Locale, "en", out displayScript, out err); string emsg = "For Locale " + newLangInfo.LocaleItems.Locale + ": "; emsg += "The script code <" + script + "> is mapping to the Icu code of <"; emsg += icuScript + ">. If you are specifying <" + displayScript; emsg += ">, please use <" + icuScript+ ">. Otherwise, "; emsg += "please use a different script code."; LogFile.AddErrorLine(emsg); throw new LDExceptions(ErrorCodes.LDUsingISO3ScriptName, emsg); } } // Check for ICU country and actual locale country key : ISO if (newLangInfo.LocaleItems.CountryKey.Length > 0) { string icuCountry, displayCountry; Icu.UErrorCode err; StringUtils.InitIcuDataDir(); // initialize ICU data dir Icu.GetCountryCode(newLangInfo.LocaleItems.Locale, out icuCountry, out err); if (newLangInfo.LocaleItems.CountryKey != icuCountry) { string country = newLangInfo.LocaleItems.CountryKey; // string isoCountry = GetISO3Country(newLangInfo.LocaleItems.Locale); Icu.GetDisplayCountry(newLangInfo.LocaleItems.Locale, "en", out displayCountry, out err); string emsg = "For Locale " + newLangInfo.LocaleItems.Locale + ": "; emsg += "The country code <" + country + "> is mapping to the Icu code of <"; emsg += icuCountry + ">. If you are specifying <" + displayCountry; emsg += ">, please use <" + icuCountry + ">. Otherwise, "; emsg += "please use a different country code."; LogFile.AddErrorLine(emsg); throw new LDExceptions(ErrorCodes.LDUsingISO3CountryName, emsg); } } // Check for ICU language and actual locale language key if (newLangInfo.LocaleItems.LangKey.Length > 0) { string icuLanguage, displayLanguage; Icu.UErrorCode err; StringUtils.InitIcuDataDir(); // initialize ICU data dir Icu.GetLanguageCode(newLangInfo.LocaleItems.Locale, out icuLanguage, out err); if (newLangInfo.LocaleItems.LangKey != icuLanguage && icuLanguage.Length > 0) { string language = newLangInfo.LocaleItems.LangKey; Icu.GetDisplayLanguage(newLangInfo.LocaleItems.Locale, "en", out displayLanguage, out err); string emsg = "For Locale " + newLangInfo.LocaleItems.Locale + ": "; emsg += "The language code <" + language + "> is mapping to the Icu code of <"; emsg += icuLanguage + ">. If you are specifying <" + displayLanguage; emsg += ">, please use <" + icuLanguage + ">. Otherwise, "; emsg += "please use a different language code."; LogFile.AddErrorLine(emsg); throw new LDExceptions(ErrorCodes.LDUsingISO3LanguageName, emsg); } } // The icuSummary variables are only true if all the iculocales are true. // The icuAddToOne variables are true if any of the iculocales are false. bool icuSummaryLang = true, icuSummaryScript = true, icuSummaryCountry = true, icuSummaryVariant = true; bool icuAddToOneLang = false, icuAddToOneScript = false, icuAddToOneCountry = false, icuAddToOneVariant = false; foreach (ICUInfo info in icuInfo) { icuSummaryLang &= info.HasLanguage; icuSummaryScript &= info.HasScript; icuSummaryCountry &= info.HasCountry; icuSummaryVariant &= info.HasVariant; icuAddToOneLang |= !info.HasLanguage; icuAddToOneScript |= !info.HasScript; icuAddToOneCountry |= !info.HasCountry; icuAddToOneVariant |= !info.HasVariant; } // custom flags bool addToCLocale = !newLangInfo.HasLocale; bool addToCLanguage = !newLangInfo.HasLanguage && !icuSummaryLang; bool addToCScript = newLangInfo.LocaleItems.ScriptKey.Length > 0 && !newLangInfo.HasScript && !icuSummaryScript; bool addToCCountry = newLangInfo.LocaleItems.CountryKey.Length > 0 && !newLangInfo.HasCountry && !icuSummaryCountry; bool addToCVariant = newLangInfo.LocaleItems.VariantKey.Length>0 && !newLangInfo.HasVariant && !icuSummaryVariant; // A. ------------------------------------------------------------ // Create the Original backups Generic.BackupOrig(rootTxtInput); Generic.BackupOrig(rootResInput); Generic.BackupOrig(resIndexTxtInput); Generic.BackupOrig(resIndexResInput); Generic.BackupOrig(xxTxtFile); Generic.BackupOrig(xxResFile); for (int iws = 0; iws < cwsNames; ++iws) { if (rgXxTxtFiles[iws] == null) continue; // would match xxTxtFile Generic.BackupOrig(rgXxTxtFiles[iws]); Generic.BackupOrig(rgXxResFiles[iws]); } // B. ------------------------------------------------------------ // Create the temporary files to serve as working copies string rootTxtTemp = Generic.CreateTempFile(rootTxtInput); // root.txt string resIndexTxtTemp = Generic.CreateTempFile(resIndexTxtInput); // res_index.txt string xxTxtTemp = Generic.CreateTempFile(xxTxtFile); // XX_YY_ZZ.txt AddTempFile(rootTxtTemp); AddTempFile(resIndexTxtTemp); AddTempFile(xxTxtTemp); string[] rgXxTxtTemps = new string[cwsNames]; for (int iws = 0; iws < cwsNames; ++iws) { if (rgXxTxtFiles[iws] == null) { rgXxTxtTemps[iws] = null; // (probably redundant...) } else { rgXxTxtTemps[iws] = Generic.CreateTempFile(rgXxTxtFiles[iws]); AddTempFile(rgXxTxtTemps[iws]); } } // C. ------------------------------------------------------------ // Create the Undo-Restore backup files string rootTxtBackup = Generic.CreateBackupFile(rootTxtInput); string rootResBackup = Generic.CreateBackupFile(rootResInput); string resIndexTxtBackup = Generic.CreateBackupFile(resIndexTxtInput); string resIndexResBackup = Generic.CreateBackupFile(resIndexResInput); string xxTxtBackup = Generic.CreateBackupFile(xxTxtFile); string xxResBackup = Generic.CreateBackupFile(xxResFile); AddUndoFileFrame(rootTxtInput, rootTxtBackup); AddUndoFileFrame(rootResInput, rootResBackup); AddUndoFileFrame(resIndexTxtInput, resIndexTxtBackup); AddUndoFileFrame(resIndexResInput, resIndexResBackup); AddUndoFileFrame(xxTxtFile, xxTxtBackup); AddUndoFileFrame(xxResFile, xxResBackup); string[] rgXxTxtBackups = new string[cwsNames]; string[] rgXxResBackups = new string[cwsNames]; for (int iws = 0; iws < cwsNames; ++iws) { if (rgXxTxtFiles[iws] == null) { rgXxTxtBackups[iws] = null; // (probably redundant...) rgXxResBackups[iws] = null; } else { rgXxTxtBackups[iws] = Generic.CreateBackupFile(rgXxTxtFiles[iws]); rgXxResBackups[iws] = Generic.CreateBackupFile(rgXxResFiles[iws]); AddUndoFileFrame(rgXxTxtFiles[iws], rgXxTxtBackups[iws]); AddUndoFileFrame(rgXxResFiles[iws], rgXxResBackups[iws]); } } int lineNumber; eAction er; // more logging information if (LogFile.IsLogging()) // put out some debuging info { LogFile.AddLine("The following changes are to be made to root.txt"); LogFile.AddLine(" - Adding to Custom Locale : " + addToCLocale.ToString()); LogFile.AddLine(" - Adding to Custom Language: " + addToCLanguage.ToString()); LogFile.AddLine(" - Adding to Custom Script : " + addToCScript.ToString()); LogFile.AddLine(" - Adding to Custom Country : " + addToCCountry.ToString()); LogFile.AddLine(" - Adding to Custom Variant : " + addToCVariant.ToString()); for (int iws = 0; iws < cwsNames; ++iws) { LogFile.AddLine("The following changes are to be made to " + rgXx[iws] + ".txt"); LogFile.AddLine(" - Adding to ICU Language: " + (!icuInfo[iws].HasLanguage).ToString()); LogFile.AddLine(" - Adding to ICU Script : " + (newLangInfo.LocaleItems.ScriptKey.Length > 0 && !icuInfo[iws].HasScript).ToString()); LogFile.AddLine(" - Adding to ICU Country : " + (newLangInfo.LocaleItems.CountryKey.Length > 0 && !icuInfo[iws].HasCountry).ToString()); LogFile.AddLine(" - Adding to ICU Variant : " + (newLangInfo.LocaleItems.VariantKey.Length > 0 && !icuInfo[iws].HasVariant).ToString()); } } //bool modifyCLanguage = false; //bool modifyCCountry = false; //bool modifyCVariant = false; //if (!addToCLanguage) //{ //} //if (!addToCCountry) //{ //} //if (!addToCVariant) //{ //} // Add the custom resources to the root text input file // Those are children of 'root.Custom' if (addToCLocale || addToCLanguage || addToCScript || addToCCountry || addToCVariant || !newLangInfo.HasCustom) { if( !m_runSlow ) { IcuDataNode rootNode = ICUDataFiles.ParsedFile(rootTxtInput); // If Custom doesn't exist, make it and it's four children if (new NodeSpecification("root","Custom").FindNode(rootNode,false) == null ) { // Get the process name for the comment string exeName = System.Diagnostics.Process.GetCurrentProcess().ProcessName; System.Globalization.CultureInfo ci = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); // the comment string comment = ""; comment += m_StartComment + NL; comment += "// This section is maintained by the '" + exeName; comment += "' Application." + NL; // Note we can't use local culture info as Korean/Chinese, etc. will introduce utf-8 // characters that will cause icu tools to fail. comment += "// Created: " + DateTime.Now.ToString("F", ci); IcuDataNode customNode = new IcuDataNode("Custom",rootNode,comment,m_EndComment + NL + NL); customNode.AddChildSmart(new IcuDataNode("LocalesAdded",customNode,"",""),false); customNode.AddChildSmart(new IcuDataNode("LanguagesAdded",customNode,"",""),false); customNode.AddChildSmart(new IcuDataNode("ScriptsAdded", customNode, "", ""), false); customNode.AddChildSmart(new IcuDataNode("CountriesAdded", customNode, "", ""), false); customNode.AddChildSmart(new IcuDataNode("VariantsAdded", customNode, "", ""), false); // Add custom to root ICUDataFiles.SetICUDataFileNode(rootTxtInput, new NodeSpecification("root"), customNode, true); } // Make all the Custom Nodes if (addToCLocale) ICUDataFiles.SetICUDataFileAttribute(rootTxtInput, new NodeSpecification("root","Custom","LocalesAdded"), newLangInfo.LocaleItems.Locale, m_comment); if (addToCLanguage) { IcuDataNode customNode = rootNode.Child("Custom"); IcuDataNode addedNames = customNode.Child("LanguagesAdded"); IcuDataNode dnXX = new IcuDataNode(newLangInfo.LocaleItems.LangKey, addedNames, "", ""); addedNames.AddChildSmart(dnXX, false); for (int iws = 0; iws < cwsNames; ++iws) { if (!icuInfo[iws].HasLanguage) // rgfAddToICULanguage[iws]) { string xx = ((StringWithWs)m_ldData.Names[iws]).icuLocale; Debug.Assert(xx != m_ldData.NewLocale); Debug.Assert(rgXxTxtFiles[iws] != null); dnXX.AddAttributeSmart( new IcuDataNode.IcuDataAttribute(xx, ", //" + m_comment + NL, true)); } } } if (addToCScript) { // If ScriptsAdded doesn't exist, make it if (new NodeSpecification("root", "Custom", "ScriptsAdded").FindNode(rootNode, false) == null) { // Get the process name for the comment string exeName = System.Diagnostics.Process.GetCurrentProcess().ProcessName; System.Globalization.CultureInfo ci = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); // the comment string comment = ""; comment += m_StartComment + NL; comment += "// This section is maintained by the '" + exeName; comment += "' Application." + NL; // Note we can't use local culture info as Korean/Chinese, etc. will introduce utf-8 // characters that will cause icu tools to fail. comment += "// Created: " + DateTime.Now.ToString("F", ci); IcuDataNode customNode = rootNode.Child("Custom"); customNode.AddChildSmart(new IcuDataNode("ScriptsAdded", customNode, "", ""), false); //// Add custom to root //ICUDataFiles.SetICUDataFileNode(rootTxtInput, new NodeSpecification("root"), customNode, true); } // first see if the script already exists, if so just add the icuLocale(s) to the attributes NodeSpecification scriptNodeSpec = new NodeSpecification("root", "Custom", "ScriptsAdded", newLangInfo.LocaleItems.ScriptKey); IcuDataNode scriptNode = scriptNodeSpec.FindNode(rootNode, false); if (scriptNode != null) { for (int iws = 0; iws < cwsNames; ++iws) { if (!icuInfo[iws].HasScript) scriptNode.AddAttribute(rgXx[iws], ", //" + m_comment + NL, true); } } else { IcuDataNode customNode = rootNode.Child("Custom"); IcuDataNode addedNames = customNode.Child("ScriptsAdded"); IcuDataNode dnXX = new IcuDataNode(newLangInfo.LocaleItems.ScriptKey, addedNames, "", ""); addedNames.AddChildSmart(dnXX, false); for (int iws = 0; iws < cwsNames; ++iws) { if (!icuInfo[iws].HasScript) { string xx = ((StringWithWs)m_ldData.Names[iws]).icuLocale; Debug.Assert(xx != m_ldData.NewLocale); Debug.Assert(rgXxTxtFiles[iws] != null); dnXX.AddAttributeSmart( new IcuDataNode.IcuDataAttribute(xx, ", //" + m_comment + NL, true)); } } } } if (addToCCountry) { // first see if the country already exists, if so just add the icuLocale(s) to the attributes NodeSpecification countryNodeSpec = new NodeSpecification("root", "Custom", "CountriesAdded", newLangInfo.LocaleItems.CountryKey); IcuDataNode countryNode = countryNodeSpec.FindNode(rootNode, false); if (countryNode != null) { for (int iws = 0; iws < cwsNames; ++iws) { if (!icuInfo[iws].HasCountry) countryNode.AddAttribute(rgXx[iws], ", //" + m_comment + NL, true); } } else { IcuDataNode customNode = rootNode.Child("Custom"); IcuDataNode addedNames = customNode.Child("CountriesAdded"); IcuDataNode dnXX = new IcuDataNode(newLangInfo.LocaleItems.CountryKey, addedNames, "", ""); addedNames.AddChildSmart(dnXX, false); for (int iws = 0; iws < cwsNames; ++iws) { if (!icuInfo[iws].HasCountry) { string xx = ((StringWithWs)m_ldData.Names[iws]).icuLocale; Debug.Assert(xx != m_ldData.NewLocale); Debug.Assert(rgXxTxtFiles[iws] != null); dnXX.AddAttributeSmart( new IcuDataNode.IcuDataAttribute(xx, ", //" + m_comment + NL, true)); } } } } if (addToCVariant) { // first see if the variant alredy exists, if so just add the icuLocale(s) to the attributes NodeSpecification variantNodeSpec = new NodeSpecification("root", "Custom", "VariantsAdded", newLangInfo.LocaleItems.VariantKey); IcuDataNode variantNode = variantNodeSpec.FindNode(rootNode, false); if (variantNode != null) { for (int iws = 0; iws < cwsNames; ++iws) { if (!icuInfo[iws].HasVariant) variantNode.AddAttribute(rgXx[iws], ", //" + m_comment + NL, true); } } else { IcuDataNode customNode = rootNode.Child("Custom"); IcuDataNode addedNames = customNode.Child("VariantsAdded"); IcuDataNode dnXX = new IcuDataNode(newLangInfo.LocaleItems.VariantKey, addedNames, "", ""); addedNames.AddChildSmart(dnXX, false); for (int iws = 0; iws < cwsNames; ++iws) { if (!icuInfo[iws].HasVariant) { string xx = ((StringWithWs)m_ldData.Names[iws]).icuLocale; Debug.Assert(xx != m_ldData.NewLocale); Debug.Assert(rgXxTxtFiles[iws] != null); dnXX.AddAttributeSmart( new IcuDataNode.IcuDataAttribute(xx, ", //" + m_comment + NL, true)); } } } } } else { // read in the root.txt file for custom resource processing string fileData = FileToString(rootTxtInput); // make sure the custom resource exists if (newLangInfo.HasCustom == false) AddCustomResource(ref fileData); if (addToCLocale) AddCustomLocale(ref fileData, newLangInfo.LocaleItems.Locale); if (addToCLanguage) AddCustomLanguage(ref fileData, newLangInfo.LocaleItems.LangKey); if (addToCScript) AddCustomScript(ref fileData, newLangInfo.LocaleItems.ScriptKey); if (addToCCountry) AddCustomCountry(ref fileData, newLangInfo.LocaleItems.CountryKey); if (addToCVariant) AddCustomVariant(ref fileData, newLangInfo.LocaleItems.VariantKey); StringToFile(rootTxtTemp, fileData); // put the file back out - with new custom resource changes } } // DN-246 Step #2 // pull out the NewLocale data and create the new locale.txt file for writing if (m_ldData.NewLocale == string.Empty || m_ldData.NewLocale.Length <= 0) { // no NewLocale information - not valid throw new LDExceptions(ErrorCodes.NewLocaleFile); } // create the output file, replace previous if one already exists // DN-246 Step #3 // Required data for locale file (in case base locale not defined) ReadAndHashString(" // Default Version" + NL + " Version { \"1.0\" }" + NL); ReadAndHashString(" // Default to English" + NL + " LocaleID:int { 0x09 }" + NL); string newLocaleAbbr_name = newLangInfo.LocaleItems.LangKey; string newLocaleAbbr_script = newLangInfo.LocaleItems.ScriptKey; string newLocaleAbbr_country = newLangInfo.LocaleItems.CountryKey; string newLocaleAbbr_variant = newLangInfo.LocaleItems.VariantKey; // If BaseLocale is populated in the LD file, fill the output file with information // from the source files for the BaseLocale name. // sample BaseLocale = "en_gb_EURO" if (m_ldData.BaseLocale != null && m_ldData.BaseLocale.Length > 0) { string baseName = ""; string baseScript = ""; string baseCountry = ""; string baseVariant = ""; string baseLocale = m_ldData.BaseLocale; ParseLocaleName(ref baseLocale, out baseName, out baseScript, out baseCountry, out baseVariant); // Read all of the base source locale files and write to the output file storage // area - m_entries. Only write to the outputfile after this process is // method has completed sucessfully. string filename = m_localeDirectory; if (baseName.Length > 0) { filename += baseName; try { ReadAndHashLocaleFile(filename + ".txt"); } catch { // just skip if the txt file doesn't exist - not required at this point } } filename += "_"; if (baseScript.Length > 0) { filename += baseScript; try { ReadAndHashLocaleFile(filename + ".txt"); } catch { // just skip if the txt file doesn't exist - not required at this point } } filename += "_"; if (baseCountry.Length > 0) { filename += baseCountry; try { ReadAndHashLocaleFile(filename + ".txt"); } catch { // just skip if the txt file doesn't exist - not required at this point } } filename += "_"; if (baseVariant.Length > 0) { filename += baseVariant; try { ReadAndHashLocaleFile(filename + ".txt"); } catch { // just skip if the txt file doesn't exist - not required at this point } } } else { } // DN-246 Step #4 // Add LocaleResources to the output area - m_entries if (m_ldData.LocaleResources != null && m_ldData.LocaleResources.Length > 0) { ReadAndHashString(m_ldData.LocaleResources); } // Add The Locale ID value to the output area - m_entries if (m_ldData.LocaleWinLCID != null && m_ldData.LocaleWinLCID.Length > 0) { string IDLine = " LocaleID:int { " + m_ldData.LocaleWinLCID + " }" + NL; ReadAndHashString(IDLine); } if( !m_runSlow ) Generic.FileCopyWithLogging(rootTxtTemp, rootTxtInput, true); // DN-246 Step #5 // This is where we update each XX.txt file with the needed locale properties: lang, country, variant. for (int iws = 0; iws < cwsNames; ++iws) { if (rgXxTxtFiles[iws] == null) { Debug.Assert(rgXx[iws] == m_ldData.NewLocale); Debug.Assert(icuInfo[iws].HasLanguage == false); // rgfAddToICULanguage[iws] == false); continue; } bool fAddOrReplace = !icuInfo[iws].HasLanguage; if (!fAddOrReplace) { // Maybe we need to modify the value? string sNew = m_ldData.LocaleName; if (sNew != null && sNew.Length > 0) { string sOld = sNew; Icu.UErrorCode uerr = Icu.UErrorCode.U_ZERO_ERROR; Icu.GetDisplayName(m_ldData.NewLocale, rgXx[iws], out sOld, out uerr); if (uerr == Icu.UErrorCode.U_ZERO_ERROR) fAddOrReplace = (sNew != sOld); } } if (fAddOrReplace) { string name = m_ldData.LocaleName; if (name == null || name.Length <= 0 ) name = newLocaleAbbr_name; ICUDataFiles.SetICUDataFileNode(rgXxTxtFiles[iws], new NodeSpecification(rgXx[iws], "Languages"), new IcuDataNode(newLocaleAbbr_name, name, "// " + m_comment), false); } // first Guess at adding the Script code fAddOrReplace = !icuInfo[iws].HasScript; if (!fAddOrReplace) { // Maybe we need to modify the value? string sNew = m_ldData.LocaleScript; if (sNew != null && sNew.Length > 0) { string sOld = sNew; Icu.UErrorCode uerr = Icu.UErrorCode.U_ZERO_ERROR; Icu.GetDisplayScript(m_ldData.NewLocale, rgXx[iws], out sOld, out uerr); if (uerr == Icu.UErrorCode.U_ZERO_ERROR) fAddOrReplace = (sNew != sOld); } } if (newLocaleAbbr_script.Length > 0 && fAddOrReplace) { string name = m_ldData.LocaleScript; if (name == null || name.Length <= 0) name = newLocaleAbbr_script; ICUDataFiles.SetICUDataFileNode(rgXxTxtFiles[iws], new NodeSpecification(rgXx[iws], "Scripts"), new IcuDataNode(newLocaleAbbr_script, name, "// " + m_comment), false); } // DN-246 Step #6 fAddOrReplace = !icuInfo[iws].HasCountry; if (!fAddOrReplace) { // Maybe we need to modify the value? string sNew = m_ldData.LocaleCountry; if (sNew != null && sNew.Length > 0) { string sOld = sNew; Icu.UErrorCode uerr = Icu.UErrorCode.U_ZERO_ERROR; Icu.GetDisplayCountry(m_ldData.NewLocale, rgXx[iws], out sOld, out uerr); if (uerr == Icu.UErrorCode.U_ZERO_ERROR) fAddOrReplace = (sNew != sOld); } } if (newLocaleAbbr_country.Length > 0 && fAddOrReplace) { string name = m_ldData.LocaleCountry; if (name == null || name.Length <= 0 ) name = newLocaleAbbr_country; ICUDataFiles.SetICUDataFileNode(rgXxTxtFiles[iws], new NodeSpecification(rgXx[iws],"Countries"), new IcuDataNode(newLocaleAbbr_country, name, "// " + m_comment),false); } // DN-246 Step #7 fAddOrReplace = !icuInfo[iws].HasVariant; if (!fAddOrReplace) { // Maybe we need to modify the value? string sNew = m_ldData.LocaleVariant; if (sNew != null && sNew.Length > 0) { string sOld = sNew; Icu.UErrorCode uerr = Icu.UErrorCode.U_ZERO_ERROR; Icu.GetDisplayVariant(m_ldData.NewLocale, rgXx[iws], out sOld, out uerr); if (uerr == Icu.UErrorCode.U_ZERO_ERROR) fAddOrReplace = (sNew != sOld); } } if (newLocaleAbbr_variant.Length > 0 && fAddOrReplace) { string name = m_ldData.LocaleVariant; if (name == null || name.Length <= 0 ) name = newLocaleAbbr_variant; ICUDataFiles.SetICUDataFileNode(rgXxTxtFiles[iws], new NodeSpecification(rgXx[iws],"Variants"), new IcuDataNode(newLocaleAbbr_variant, name, "// " + m_comment),false); } } // DN-246 Step #8 // Produce the XXX.txt file. Close the output file. WriteLocaleFile(m_ldData.NewLocale, xxTxtTemp); if( !m_runSlow ) { ICUDataFiles.SetICUDataFileNode(resIndexTxtInput, new NodeSpecification("res_index:table(nofallback)","InstalledLocales"), new IcuDataNode(m_ldData.NewLocale, "", "// " + m_comment),false); } else { // Add to res_index.txt file if not already present. er = FindResource(resIndexTxtInput, "InstalledLocales", m_ldData.NewLocale, "", out lineNumber); ModifyFile(resIndexTxtInput, resIndexTxtTemp, lineNumber, " " + m_ldData.NewLocale + " {\"\"}", er, ErrorCodes.ResIndexFile); } if( !m_runSlow ) { // Write all Files for all steps so far ICUDataFiles.WriteFiles(); // Copy to the temp files because these are what we are going to use. Generic.FileCopyWithLogging(rootTxtInput,rootTxtTemp,true); Generic.FileCopyWithLogging(resIndexTxtInput,resIndexTxtTemp,true); for (int iws = 0; iws < cwsNames; ++iws) { if (rgXxTxtTemps[iws] != null) Generic.FileCopyWithLogging(rgXxTxtFiles[iws], rgXxTxtTemps[iws], true); } } // DN-246 Step #9 - generate .res files // Process all files together and catch errors. ArrayList Files = new ArrayList(); Files.Add(resIndexTxtTemp); Files.Add(xxTxtTemp); Files.Add(rootTxtTemp); for (int iws = 0; iws < cwsNames; ++iws) { if (rgXxTxtTemps[iws] != null) Files.Add(rgXxTxtTemps[iws]); } GenerateResFile(Files, m_localeDirectory, m_icuBase + m_IcuData, ErrorCodes.GeneralFile, "InstallLDFile"); Generic.FileCopyWithLogging(rootTxtTemp, rootTxtInput, true); Generic.FileCopyWithLogging(resIndexTxtTemp, resIndexTxtInput, true); Generic.FileCopyWithLogging(xxTxtTemp, xxTxtFile, true); for (int iws = 0; iws < cwsNames; ++iws) { if (rgXxTxtTemps[iws] != null) Generic.FileCopyWithLogging(rgXxTxtTemps[iws], rgXxTxtFiles[iws], true); } // FINAL STEP: Check for Collation information. string sColl = m_ldData.CollationElements; // Note, if we already have a collation file, we need to process it again in case // the user removed all collation elements to revert to the default collation. string colFile = m_collDirectory + m_ldData.NewLocale + ".txt"; if (File.Exists(colFile) || sColl != null && sColl != "") InstallCollation(); else if (m_ldData.BaseLocale != null && File.Exists(m_collDirectory + m_ldData.BaseLocale + ".txt")) { // make sure if it has a baselocale - and that has a collation - use it InstallCollation(); } }
private void GetModifiedLocales(IcuDataNode rootNode, string section, string locale, ArrayList rgXxTxtFiles, ArrayList rgXxResFiles) { IcuDataNode customNode = rootNode.Child("Custom"); if (customNode == null) return; IcuDataNode sectionNode = customNode.Child(section); if (sectionNode == null) return; IcuDataNode localeNode = sectionNode.Child(locale); if (localeNode == null) return; IList rgAtts = localeNode.Attributes; for (int i = 0; i < rgAtts.Count; ++i) { IcuDataNode.IcuDataAttribute x = rgAtts[i] as IcuDataNode.IcuDataAttribute; if (x.StringValue != null) { string txtFile = m_localeDirectory + x.StringValue + ".txt"; if (!rgXxTxtFiles.Contains(txtFile)) { rgXxTxtFiles.Add(txtFile); string resFile = m_icuBase + m_IcuData + x.StringValue + ".res"; rgXxResFiles.Add(resFile); } } } }
private void GetXXLangsForICULocalePortion(IcuDataNode rootNode, LocalePortion portion, string localeKey, ref Hashtable xxFiles) { string customChild = LocalePortionAsString(portion); NodeSpecification node = new NodeSpecification("root", "Custom", customChild, localeKey); IcuDataNode dataNode = node.FindNode(rootNode, false); if (dataNode != null) { // get the list of xx.txt files to edit in this section foreach (IcuDataNode.IcuDataAttribute attr in dataNode.Attributes) { xxFileInfo xxFile; string xx = attr.StringValue; // the lang code {ex: "en"} if (xxFiles.ContainsKey(xx)) { xxFile = xxFiles[xx] as xxFileInfo; } else { xxFile = new xxFileInfo(xx); xxFiles[xx] = xxFile; } if (portion == LocalePortion.Variant) { xxFile.rmFromVariant = true; xxFile.xxVariantKey = localeKey; } else if (portion == LocalePortion.Lang) { xxFile.rmFromLang = true; xxFile.xxLangKey = localeKey; } else if (portion == LocalePortion.Script) { xxFile.rmFromScript = true; xxFile.xxScriptKey = localeKey; } else if (portion == LocalePortion.Country) { xxFile.rmFromCountry = true; xxFile.xxCountryKey = localeKey; } } // remove the key from the section of custom in root.txt if (!ICUDataFiles.RemoveICUDataFileChild(rootNode, new NodeSpecification("root", "Custom", customChild), localeKey)) { LogFile.AddVerboseLine("***Unable to remove <"+localeKey+"> from the <"+customChild+"> section in the root.txt"); } } }