/*
* Helpers.cs
* Authors: Benjamin Nitschke (copied from various classes at abi.exdream.com)
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Globalization;
using System.IO;
namespace Pina3D
{
///
/// Xml helper. Virtually unchanged classes downloaded from abi.exdream.com, which much of his other code in this project utilizes.
///
internal class XmlHelper
{
///
/// Private constructor to prevent instantiation.
///
private XmlHelper()
{
}
///
/// Get xml attribute with help of currently open xml reader and
/// attributeName. If attribute does not exists an empty string is
/// returned.
///
/// Reader
/// Attribute name
/// String
public static string GetXmlAttribute(
XmlReader reader,
string attributeName)
{
string ret = reader.GetAttribute(attributeName);
return ret == null ? "" : ret;
}
///
/// Get xml int value, will return 0 if it does not exists or
/// isn't an int. Will use the "value" attribute.
///
/// Reader
/// Float
public static int GetXmlIntValue(XmlReader reader)
{
string str = reader.GetAttribute("value");
int ret = 0;
//int.TryParse(str, out ret);
if (StringHelper.IsNumericInt(str))
ret = Convert.ToInt32(str);
return ret;
} // GetXmlIntValue(reader)
///
/// Get xml float value, will return 0 if it does not exists or
/// isn't a float. Will use the "value" attribute.
///
/// Reader
/// Float
public static float GetXmlFloatValue(XmlReader reader)
{
string str = reader.GetAttribute("value");
float ret = 0;
//float.TryParse(str, out ret);
if (StringHelper.IsNumericFloat(str))
ret = Convert.ToSingle(str, NumberFormatInfo.InvariantInfo);
return ret;
}
///
/// Find node in the root level of the xml document (main nodes)
///
/// Xml doc
/// Xml node name
/// Xml node
public static XmlNode FindNodeInRoot(XmlDocument xmlDoc,
string xmlNodeName)
{
if (xmlDoc == null)
return null;
foreach (XmlNode node in xmlDoc.ChildNodes)
if (StringHelper.Compare(node.Name, xmlNodeName))
return node;
// Not found
return null;
}
///
/// Find node recursively in a xml document by its name.
///
/// Xml document
/// Xml node name
/// Xml node or null if not found
public static XmlNode FindNode(XmlNode xmlDoc, string xmlNodeName)
{
if (xmlDoc == null)
return null;
foreach (XmlNode node in xmlDoc.ChildNodes)
{
if (String.Compare(node.Name, xmlNodeName, true) == 0)
return node;
XmlNode foundChildNode = FindNode(node, xmlNodeName);
if (foundChildNode != null)
return foundChildNode;
}
// Not found at all.
return null;
}
///
/// Get xml attribute, will return "" if not found.
///
/// Node
/// Attribute name
/// String
public static string GetXmlAttribute(
XmlNode node, string attributeName)
{
if (node == null || node.Attributes == null)
return "";
foreach (XmlNode attribute in node.Attributes)
if (StringHelper.Compare(attribute.Name, attributeName))
return attribute.Value == null ? "" : attribute.Value;
// Not found, just return empty string
return "";
}
///
/// Get xml int value, will return 0 if it does not exists or
/// isn't an int. Will use the "value" attribute.
///
/// Node
/// Float
public static int GetXmlIntValue(XmlNode node)
{
string str = GetXmlAttribute(node, "value");
int ret = 0;
//int.TryParse(str, out ret);
if (StringHelper.IsNumericInt(str))
ret = Convert.ToInt32(str);
return ret;
}
///
/// Get xml float value, will return 0 if it does not exists or
/// isn't a float. Will use the "value" attribute.
///
/// Node
/// Float
public static float GetXmlFloatValue(XmlNode node)
{
string str = GetXmlAttribute(node, "value");
float ret = 0;
//float.TryParse(str, out ret);
if (StringHelper.IsNumericFloat(str))
ret = Convert.ToSingle(str, NumberFormatInfo.InvariantInfo);
return ret;
}
///
/// Create xml document with declaration (version 1.0, utf-8).
///
/// Created xml document
public static XmlDocument CreateXmlDocumentWithDeclaration()
{
XmlDocument xmlDoc = new XmlDocument();
// Insert declaration as first element
xmlDoc.InsertBefore(
xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null),
xmlDoc.DocumentElement);
return xmlDoc;
}
///
/// Create parent node
///
/// Xml doc
/// Node name
/// Xml node
public static XmlNode CreateParentNode(XmlDocument xmlDoc, string nodeName)
{
XmlElement parentNode = xmlDoc.CreateElement(nodeName);
xmlDoc.AppendChild(parentNode);
return parentNode;
}
///
/// Create empty parent node named "ParentNode" on an empty xml document.
///
/// Xml node
public static XmlNode CreateEmptyParentNode()
{
// Create empty xml document
XmlDocument xmlDoc = CreateXmlDocumentWithDeclaration();
// Create parent node, don't add it do xmlDoc, we dispose it anyway.
return xmlDoc.CreateElement("ParentNode");
}
///
/// Get xml document from any node, even the xml document itself.
///
/// Some node
/// Xml document
public static XmlDocument GetXmlDocument(XmlNode someNode)
{
if (someNode == null)
throw new ArgumentNullException("someNode",
"Can't get xml document without valid node");
// Check if someNode is our XmlDocument
XmlDocument xmlDoc = someNode as XmlDocument;
// If not, use the OwnerDocument property
if (xmlDoc == null)
xmlDoc = someNode.OwnerDocument;
return xmlDoc;
}
///
/// Create child node, will get xml document from parentNode.
///
/// Parent node
/// Child node name
/// Xml node
public static XmlNode CreateChildNode(
XmlNode parentNode,
string childNodeName)
{
// Create child node
XmlNode childNode =
GetXmlDocument(parentNode).CreateElement(childNodeName);
// Add it to parent
parentNode.AppendChild(childNode);
// And return it
return childNode;
}
///
/// Create node with attribute
///
/// Xml document
/// Node name
/// Attribute name
/// Attribute value
/// Xml node
public static XmlNode CreateNodeWithAttribute(XmlDocument xmlDoc,
string nodeName, string attributeName, string attributeValue)
{
XmlElement node = xmlDoc.CreateElement(nodeName);
XmlAttribute attribute = xmlDoc.CreateAttribute(attributeName);
attribute.Value = attributeValue;
node.Attributes.Append(attribute);
return node;
}
///
/// Load xml from text and returns the first useable root (not the xml
/// document).
///
/// Xml text
public static XmlNode LoadXmlFromText(string xmlText)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlText);
return GetRootXmlNode(xmlDoc);
}
///
/// Load xml from file
///
/// Xml filename
/// Xml node
public static XmlNode LoadXmlFromFile(string xmlFilename)
{
XmlDocument xmlDoc = new XmlDocument();
if (File.Exists(xmlFilename))
xmlDoc.Load(File.Open(xmlFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
return GetRootXmlNode(xmlDoc);
}
///
/// Get child node
///
/// Root node
/// Child name
/// Xml node
public static XmlNode GetChildNode(XmlNode rootNode, string childName)
{
if (rootNode == null)
throw new ArgumentNullException("rootNode",
"Need valid rootNode for GetChildNode.");
foreach (XmlNode node in rootNode.ChildNodes)
{
if (node.Name == childName)
return node;
if (node.ChildNodes != null &&
node.ChildNodes.Count > 0)
{
XmlNode result = GetChildNode(node, childName);
if (result != null)
return result;
}
}
// Not found, return null
return null;
}
///
/// Get child node. This version does not search for a child node name,
/// but instead we check if we can find any child with the
/// attribute name and value as specified.
///
/// Root node
/// Child attribute name
/// Child attribute value
/// Xml node
public static XmlNode GetChildNode(XmlNode rootNode,
string childAttributeName, string childAttributeValue)
{
if (rootNode == null)
throw new ArgumentNullException("rootNode",
"Need valid rootNode for GetChildNode.");
foreach (XmlNode node in rootNode.ChildNodes)
{
if (GetXmlAttribute(node, childAttributeName) == childAttributeValue)
return node;
if (node.ChildNodes != null &&
node.ChildNodes.Count > 0)
{
XmlNode result = GetChildNode(node,
childAttributeName, childAttributeValue);
if (result != null)
return result;
}
}
// Not found, return null
return null;
}
///
/// Get root xml node (not the xml document, but the first useable root)
///
/// Xml node
public static XmlNode GetRootXmlNode(XmlNode xmlNode)
{
if (xmlNode == null)
throw new ArgumentNullException("xmlNode",
"Need valid xmlNode for GetRootXmlNode.");
// Not a document type? Then jump back to document type.
if (xmlNode.NodeType != XmlNodeType.Document)
{
return GetRootXmlNode(xmlNode.OwnerDocument);
}
foreach (XmlNode node in xmlNode.ChildNodes)
{
if (node.NodeType != XmlNodeType.XmlDeclaration &&
node.NodeType != XmlNodeType.ProcessingInstruction)
{
return node;
}
}
// Nothing found? Then return original node, there isn't any real node
// available yet.
return xmlNode;
}
private const string DefaultDirectoryAttributeName = "Directory";
///
/// Get directory attribute
///
/// Node
/// String
public static string GetDirectoryAttribute(XmlNode node)
{
string ret = GetXmlAttribute(node, DefaultDirectoryAttributeName);
if (String.IsNullOrEmpty(ret))
{
foreach (XmlNode childNode in node.ChildNodes)
if (StringHelper.Compare(childNode.Name,
DefaultDirectoryAttributeName))
return childNode.Value;
}
return ret;
}
///
/// Write xml to string. Will return the whole xml document content
/// as a string. Declaration stuff is cut out, but everything else
/// is the same as written to the file when calling xmlDoc.Save.
///
/// Xml doc
/// String
public static string WriteXmlToString(XmlDocument xmlDoc)
{
if (xmlDoc == null)
throw new ArgumentNullException("xmlDoc",
"WriteXmlToString requires a valid xml document.");
// Save xmlDoc to a memory stream
MemoryStream memStream = new MemoryStream();
xmlDoc.Save(memStream);
// Put it into a text reader
memStream.Seek(0, SeekOrigin.Begin);
TextReader textReader = new StreamReader(memStream);
// And read everything
int lineNumber = 0;
string ret = "";
while (textReader.Peek() >= 0)
{
string line = textReader.ReadLine();
lineNumber++;
// Skip first line (xml version and stuff)
if (lineNumber == 1 &&
line.Length < 200 &&
(line.StartsWith("
line = line.Replace("<", "<").Replace(">", ">");
// Else just add to return string
ret += (ret.Length == 0 ? "" : StringHelper.NewLine) + line;
} // while (textReader.Peek)
return ret;
}
///
/// Convert xml type to string
///
/// Type value
/// String
public static string ConvertXmlTypeToString(object typeValue)
{
// Special save handling only for the date (at the moment)
if (typeValue.GetType() == new DateTime().GetType())
{
DateTime date = (DateTime)typeValue;
return date.Year + "-" +
date.Month.ToString("00") + "-" +
date.Day.ToString("00");
}
else
{
return typeValue.ToString();
}
}
}
///
/// Downloaded from abi.exdream.com. Many unused functions were deleted from the original class.
/// StringHelper: Provides additional or simplified string functions.
/// This class does also offer a lot of powerful functions and
/// allows complicated string operations.
/// Easy functions at the beginning, harder ones later.
///
public class StringHelper
{
public const string NewLine = "\r\n";
///
/// Don't allow instantiating this class.
///
private StringHelper()
{
}
///
/// Check if a string (s1, can be longer as s2) begins with another
/// string (s2), only if s1 begins with the same string data as s2,
/// true is returned, else false. The string compare is case insensitive.
///
static public bool BeginsWith(string s1, string s2)
{
return String.Compare(s1, 0, s2, 0, s2.Length, true,
CultureInfo.CurrentCulture) == 0;
}
///
/// Helps to compare strings, uses case insensitive comparison.
/// String.
///
static public bool Compare(string s1, string s2)
{
return String.Compare(s1, s2, true,
CultureInfo.CurrentCulture) == 0;
}
///
/// Convert string data to int array, string must be in the game
/// "1, 3, 8, 7", etc. WriteArrayData is the complementar function.
///
/// int array, will be null if string is invalid!
static public int[] ConvertStringToIntArray(string s)
{
// Invalid?
if (s == null || s.Length == 0)
return null;
string[] splitted = s.Split(new char[] { ' ' });
int[] ret = new int[splitted.Length];
for (int i = 0; i < ret.Length; i++)
if (String.IsNullOrEmpty(splitted[i]) == false)
{
try
{
ret[i] = Convert.ToInt32(splitted[i]);
}
catch { }
}
return ret;
}
///
/// Convert string data to float array, string must be in the game
/// "1.5, 3.534, 8.76, 7.49", etc. WriteArrayData is the complementar
/// function.
///
/// float array, will be null if string is invalid!
static public float[] ConvertStringToFloatArray(string s)
{
// Invalid?
if (s == null || s.Length == 0)
return null;
string[] splitted = s.Split(new char[] { ' ' });
float[] ret = new float[splitted.Length];
for (int i = 0; i < ret.Length; i++)
if (String.IsNullOrEmpty(splitted[i]) == false)
{
try
{
ret[i] = Convert.ToSingle(splitted[i],
CultureInfo.InvariantCulture);
}
catch { }
}
return ret;
}
///
/// Extracts filename from full path+filename, cuts of extension
/// if cutExtension is true. Can be also used to cut off directories
/// from a path (only last one will remain).
///
static public string ExtractFilename(string pathFile, bool cutExtension)
{
if (pathFile == null)
return "";
// Also checking for normal slashes, needed for support reading 3ds max stuff.
string[] fileName = pathFile.Split(new char[] { '\\', '/' });
if (fileName.Length == 0)
{
if (cutExtension)
return CutExtension(pathFile);
return pathFile;
}
if (cutExtension)
return CutExtension(fileName[fileName.Length - 1]);
return fileName[fileName.Length - 1];
}
///
/// Cut of extension, e.g. "hi.txt" becomes "hi"
///
static public string CutExtension(string file)
{
if (file == null)
return "";
int l = file.LastIndexOf('.');
if (l > 0)
return file.Remove(l, file.Length - l);
return file;
}
///
/// Is numeric float
///
/// Str
/// Bool
public static bool IsNumericFloat(string str)
{
return IsNumericFloat(str, CultureInfo.InvariantCulture.NumberFormat);
}
///
/// Allow only one decimal point, used for IsNumericFloat.
///
/// Input string to check
/// Used number format, e.g.
/// CultureInfo.InvariantCulture.NumberFormat
/// True if check succeeded, false otherwise
private static bool AllowOnlyOneDecimalPoint(string str,
NumberFormatInfo numberFormat)
{
char[] strInChars = str.ToCharArray();
bool hasGroupSeperator = false;
int decimalSeperatorCount = 0;
for (int i = 0; i < strInChars.Length; i++)
{
if (numberFormat.CurrencyDecimalSeparator.IndexOf(strInChars[i]) == 0)
{
decimalSeperatorCount++;
}
// has float group seperators ?
if (numberFormat.CurrencyGroupSeparator.IndexOf(strInChars[i]) == 0)
{
hasGroupSeperator = true;
}
}
if (hasGroupSeperator)
{
// If first digit is the group seperator or begins with 0,
// there is something wrong, the group seperator is used as a comma.
if (str.StartsWith(numberFormat.CurrencyGroupSeparator) ||
strInChars[0] == '0')
return false;
// look only at the digits in front of the decimal point
string[] splittedByDecimalSeperator = str.Split(
numberFormat.CurrencyDecimalSeparator.ToCharArray());
// ==> 1.000 -> 000.1 ==> only after 3 digits
char[] firstSplittedInChars = splittedByDecimalSeperator[0].ToCharArray();
int arrayLength = firstSplittedInChars.Length;
char[] firstSplittedInCharsInverted = new char[arrayLength];
for (int i = 0; i < arrayLength; i++)
{
firstSplittedInCharsInverted[i] =
firstSplittedInChars[arrayLength - 1 - i];
}
// group seperators are only allowed between 3 digits -> 1.000.000
for (int i = 0; i < arrayLength; i++)
{
if (i % 3 != 0 && numberFormat.CurrencyGroupSeparator.IndexOf(
firstSplittedInCharsInverted[i]) == 0)
{
return false;
}
}
}
if (decimalSeperatorCount > 1)
return false;
return true;
}
///
/// Checks if string is numeric float value
///
/// Input string
/// Used number format, e.g.
/// CultureInfo.InvariantCulture.NumberFormat
/// True if str can be converted to a float,
/// false otherwise
public static bool IsNumericFloat(string str,
NumberFormatInfo numberFormat)
{
// Can't be a float if string is not valid!
if (String.IsNullOrEmpty(str))
return false;
// Only 1 decimal point is allowed
if (AllowOnlyOneDecimalPoint(str, numberFormat) == false)
return false;
// + allows in the first,last,don't allow in middle of the string
// - allows in the first,last,don't allow in middle of the string
// $ allows in the first,last,don't allow in middle of the string
// , allows in the last,middle,don't allow in first char of the string
// . allows in the first,last,middle, allows in all the indexs
bool retVal = false;
// If string is just 1 letter, don't allow it to be a sign
if (str.Length == 1 &&
"+-$.,".IndexOf(str[0]) >= 0)
return false;
for (int i = 0; i < str.Length; i++)
{
// For first indexchar
char pChar =
//char.Parse(str.Substring(i, 1));
Convert.ToChar(str.Substring(i, 1));
if (retVal)
retVal = false;
if ((!retVal) && (str.IndexOf(pChar) == 0))
{
retVal = ("+-$.0123456789".IndexOf(pChar) >= 0) ? true : false;
}
// For middle characters
if ((!retVal) && (str.IndexOf(pChar) > 0) &&
(str.IndexOf(pChar) < (str.Length - 1)))
{
retVal = (",.0123456789".IndexOf(pChar) >= 0) ? true : false;
}
// For last characters
if ((!retVal) && (str.IndexOf(pChar) == (str.Length - 1)))
{
retVal = ("+-$,.0123456789".IndexOf(pChar) >= 0) ? true : false;
}
if (!retVal)
break;
}
return retVal;
}
///
/// Check if string is numeric integer. A decimal point is not accepted.
///
/// String to check
public static bool IsNumericInt(string str)
{
// Can't be an int if string is not valid!
if (String.IsNullOrEmpty(str))
return false;
// Go through every letter in str
int strPos = 0;
foreach (char ch in str)
{
// Only 0-9 are allowed
if ("0123456789".IndexOf(ch) < 0 &&
// Allow +/- for first char
(strPos > 0 || (ch != '-' && ch != '+')))
return false;
strPos++;
}
// All fine, return true, this is a number!
return true;
}
}
}