SIL.FieldWorks.UnicodeCharEditor.PUAInstaller.ModifyUCDFile C# (CSharp) Method

ModifyUCDFile() private method

This function will add or remove the given PUA characters from the given DerivedBidiClass.txt file by either inserting or not inserting them as necessary as it reads through the file in a single pass from tr to tw.
Assumptions The like Bidi values are grouped together Non Assumptions: That comments add any information to the file. We don't use comments for parsing. That "blank" lines appear only between different bidi value sections. That the comments should be in the format: # field2 [length of range] Name_of_First_Character..Name_of_Last_Charachter (If it is not, we'll just ignore.
private ModifyUCDFile ( TextReader tr, TextWriter tw, List ucdCharacters, bool add ) : void
tr TextReader A reader with information DerivedBidiData.txt
tw System.IO.TextWriter A writer with information to write to DerivedBidiData.txt
ucdCharacters List A list of PUACharacters to either add or remove from the file
add bool Whether to add or remove the given characters
return void
		private void ModifyUCDFile(TextReader tr, TextWriter tw,
			List<IUcdCharacter> ucdCharacters, bool add)
		{
			if (ucdCharacters.Count == 0)
			{
				// There is no point in processing this file if we aren't going to do anything to it.
				tw.Write(tr.ReadToEnd());
				// Allows us to know that there will be at least on ucdCharacter that we can access to get some properties
				return;
			}

			//contains our current line
			// not null so that we get into the while loop
			var line = "unused value";
			//Bidi class value from the previous line
			var lastProperty = "blank";
			//Bidi class value from the current line

			// the index of the IPuaCharacter the we are currently trying to insert
			// Note, the initial value will never be used, because there will be no
			//		bidi class value called "blank" in the file, thus it will be initialized before it is every used
			//		but VS requires an initialization value "just in case"
			int codeIndex = -1;
			// If we have read in the line already we want to use this line for the loop, set this to be true.
			bool dontRead = false;

			//Count the number of characters in each range
			int rangeCount = 0;

			//While there is a line to be read in the file

			while ((dontRead && line != null) || (line = tr.ReadLine()) != null)
			{
				dontRead = false;
				if (HasBidiData(line))
				{
					// We found another valid codepoint, increment the count
					IncrementCount(ref rangeCount, line);

					var currentProperty = GetProperty(line);

					// If this is a new section of bidi class values
					if (!ucdCharacters[0].SameRegion(currentProperty, lastProperty))
					{
						lastProperty = currentProperty;
						// Find one of the ucdCharacters in this range in the list of ucdCharacters to add.
						var fFound = false;
						for (codeIndex = 0; codeIndex < ucdCharacters.Count; codeIndex++)
						{
							var ch = ucdCharacters[codeIndex];
							if (ch != null && ch.CompareTo(currentProperty) == 0)
							{
								fFound = true;
								break;
							}
						}

						// if we don't have any characters to put in this section
						if (!fFound)
						{
							tw.WriteLine(line);
							line = ReadToEndOfSection(tr, tw, lastProperty, rangeCount, ucdCharacters[0]);
							rangeCount = 0;
							dontRead = true;
							continue;
						}
					}

					#region insert_the_PUACharacter
					//Grab codepoint
					string code = line.Substring(0, line.IndexOf(';')).Trim();

					//If it's a range of codepoints
					if (code.IndexOf('.') != -1)
					{
						#region if_range
						//Grabs the end codepoint
						string endCode = code.Substring(code.IndexOf("..") + 2).Trim();
						code = code.Substring(0, code.IndexOf("..")).Trim();

						//A dynamic array that contains our range of codepoints and the properties to go with it
						var codepointsWithinRange = new List<IUcdCharacter>();

						// If the IPuaCharacter we want to insert is before the range
						while (
							//If this is the last one stop looking for more
							StillInRange(codeIndex, ucdCharacters, currentProperty) &&
							// For every character before the given value
							(ucdCharacters[codeIndex]).CompareCodePoint(code) < 0
							)
						{
							//Insert characters before the code
							AddUCDLine(tw, ucdCharacters[codeIndex], add);
							codeIndex++;
						}
						while (
							//If this is the last one stop looking for more
							StillInRange(codeIndex, ucdCharacters, currentProperty) &&
							// While our xmlCodepoint satisfies: code <= xmlCodepoint <= endCode
							(ucdCharacters[codeIndex]).CompareCodePoint(endCode) < 1
							)
						{
							//Adds the puaCharacter to the list of codepoints that are in range
							codepointsWithinRange.Add(ucdCharacters[codeIndex]);
							codeIndex++;
						}
						//If we found any codepoints in the range to insert
						if (codepointsWithinRange.Count > 0)
						{
							#region parse_comments
							//Do lots of smart stuff to insert the PUA characters into the block
							string generalCategory = "";
							//Contains the beginning and ending range names
							string firstName = "";
							string lastName = "";

							//If a comment exists on the line in the proper format
							// e.g.   ---  # --- [ --- ] --- ... ---
							if (line.IndexOf('#') != -1 && line.IndexOf('[') != -1
								&& (line.IndexOf('#') <= line.IndexOf('[')))
							{
								//Grabs the general category
								generalCategory = line.Substring(line.IndexOf('#') + 1, line.IndexOf('[') - line.IndexOf('#') - 1).Trim();
							}
							//find the index of the second ".." in the line
							int indexDotDot = line.Substring(line.IndexOf(']')).IndexOf("..");
							if (indexDotDot != -1)
								indexDotDot += line.IndexOf(']');

							//int cat = line.IndexOf(']') ;

							if (line.IndexOf('#') != -1 && line.IndexOf('[') != -1 && line.IndexOf(']') != -1 && indexDotDot != -1
								&& (line.IndexOf('#') < line.IndexOf('['))
								&& (line.IndexOf('[') < line.IndexOf(']'))
								&& (line.IndexOf(']') < indexDotDot)
								)
							{
								//Grab the name of the first character in the range
								firstName = line.Substring(line.IndexOf(']') + 1, indexDotDot - line.IndexOf(']') - 1).Trim();
								//Grab the name of the last character in the range
								lastName = line.Substring(indexDotDot + 2).Trim();
							}
							#endregion
							WriteBidiCodepointBlock(tw, code, endCode, codepointsWithinRange,
								generalCategory, firstName, lastName, add);
						}
						else
						{
							tw.WriteLine(line);
						}
						#endregion
					}
					//if the codepoint in the file is equal to the codepoint that we want to insert
					else
					{
						if (MiscUtils.CompareHex(code, ucdCharacters[codeIndex].CodePoint) > 0)
						{
							// Insert the new PuaDefinition before the line (as well as any others that might be)
							while (
								//If this is the last one stop looking for more
								StillInRange(codeIndex, ucdCharacters, currentProperty) &&
								// For every character before the given value
								ucdCharacters[codeIndex].CompareCodePoint(code) < 0
								)
							{
								//Insert characters before the code
								AddUCDLine(tw, ucdCharacters[codeIndex], add);
								codeIndex++;
							}
						}
						//if the codepoint in the file is equal to the codepoint that we want to insert
						if (StillInRange(codeIndex, ucdCharacters, currentProperty) &&
							(code == ucdCharacters[codeIndex].CodePoint))
						{
							// Replace the line with the new PuaDefinition
							AddUCDLine(tw, ucdCharacters[codeIndex], add);
							// Look for the next PUA codepoint that we wish to insert
							codeIndex++;
						}
						//if it's not a first tag and the codepoints don't match
						else
						{
							tw.WriteLine(line);
						}
					}

					//If we have no more codepoints to insert in this section, then just finish writing this section
					if (!StillInRange(codeIndex, ucdCharacters, currentProperty))
					{
						line = ReadToEndOfSection(tr, tw, lastProperty, rangeCount, ucdCharacters[0]);
						rangeCount = 0;
						dontRead = true;
						continue;
					}
					#endregion
				}
				//If it's a comment, simply write it out
				else
				{
					// find the total count comment and replace it with the current count.
					if (line.ToLowerInvariant().IndexOf("total code points") != -1)
					{
						line = "# Total code points:" + rangeCount;
						rangeCount = 0;
					}
					tw.WriteLine(line);
				}
			}
		}