コード例 #1
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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);
				}
			}
		}
コード例 #2
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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();
		}
コード例 #3
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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;
				}
			}
		}
コード例 #4
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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);
			}
		}
コード例 #5
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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;
		}
コード例 #6
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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);
		}
コード例 #7
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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);
			}
		}
コード例 #8
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		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);
		}
コード例 #9
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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;
		}
コード例 #10
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		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);
		}
コード例 #11
0
ファイル: ICUDataFile.cs プロジェクト: sillsdev/WorldPad
		/// <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);
		}
コード例 #12
0
ファイル: LocaleFile.cs プロジェクト: sillsdev/WorldPad
		/// <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();
			}
		}
コード例 #13
0
ファイル: LocaleFile.cs プロジェクト: sillsdev/WorldPad
		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);
					}
				}
			}
		}
コード例 #14
0
ファイル: LocaleFile.cs プロジェクト: sillsdev/WorldPad
		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");
				}

			}
		}