1 °³¿ä
C++¿ë YAML ÆÄ¼¸¦ C# ¿ëÀ¸·Î ¹Ù²ãºÃ´Ù. ÀÚ¼¼ÇÑ ³»¿ëÀº YamlParserForCpp ÆäÀÌÁö¸¦ Âü°í. C#¿¡´Â ¾ÆÁ÷ Àͼ÷ÇÑ ÆíÀÌ ¾Æ´Ï¶ó, °íÄ¥ Á¡ Åõ¼ºÀÌÀÏ µí. ÆÄ½ÌÇÒ ¶§ ±×³É ¹®ÀÚ¿ÀÌ ¾Æ´Ï¶ó, Á¤±Ô½Ä »ç¿ëÇϸé Á» ´õ ±ò²ûÇÒ±î?
2 ¼Ò½º
////////////////////////////////////////////////////////////////////////////////
// File : YamlTree.cs
// Author : ±è¼º¹Î (http://serious-code.net)
// Desc : °£´Ü YAML ÆÄ¼
// Created : 2006-07-24
// Last Update : 2006-07-24
////////////////////////////////////////////////////////////////////////////////
namespace Yaml
{
/// <summary>
/// °£´ÜÇÑ YAML ÆÄ¼. XML ÂÊÀÇ DOM ÆÄ¼¸¦ »ý°¢ÇÏ¸é µÈ´Ù. Áï ¹®¼¸¦ Åëä·Î
/// ·ÎµåÇØ¼ ¸Þ¸ð¸® »ó¿¡ Æ®¸® ÇüÅ·Π±¸¼ºÇÏ´Â ÆÄ¼ÀÌ´Ù.
///
/// XML ÆÄÀÏÀÌ ³Ê¹« ÁöÀúºÐÇÑ °æÇâÀÌ ÀÖ¾î, ´ë¾ÈÀ» ã´Ù°¡ YAMLÀ̶ó´Â °ÍÀ»
/// ¾Ë°Ô µÇ¾ú´Ù. ¹®¹ýÀÌ ±ò²ûÇϱâ´Â Çѵ¥, C/C++ ÆÄ¼°¡ ÇöÀç Á¸ÀçÇÏÁö ¾Ê¾Æ¼
/// ´ëÃæ ¾²´Â ±â´Éµé¸¸ ¸ð¾Æ¼ Çѹø ¸¸µé¾îºÃ´Ù. ÇöÀç Áö¿øÇÏ´Â ±â´ÉÀ» º¸ÀÚ¸é
/// ´ÙÀ½°ú °°´Ù.
///
/// - ±âº»ÀûÀÎ scalar, sequence, mapping Áö¿ø
/// - Block scalar ¹× folded scalar Áö¿ø
/// - Anchor & alias Áö¿ø
/// - ¶óÀÎ ÁÖ¼® Áö¿ø
///
/// ÀÚ½Ä ³ëµå´Â ¸Ê ÇüÅ ¶Ç´Â ¹è¿ ÇüÅ·Π¾×¼¼½ºÇÒ ¼ö ÀÖ´Ù. µÑÀ» È¥¿ëÇÒ ¼ö´Â
/// ¾ø´Ù. ±âº»ÀûÀ¸·Î´Â Ű ¹®ÀÚ¿À» ÀÌ¿ëÇØ ¸Ê ÇüÅ·ΠÀÚ½Ä ³ëµåµéÀ» µÎ°Ô µÈ´Ù.
/// ÀÌ´Â °°Àº À̸§(key)ÀÇ ÀÚ½Ä ³ëµå°¡ 2°³ ÀÌ»ó ÀÖ´Â °æ¿ì, ±× Áß¿¡ Çϳª¸¸
/// ¼±ÅõÊÀ» ÀǹÌÇÑ´Ù. Ruby¿¡ ÀÖ´Â YAML ÆÄ¼ °°Àº °æ¿ì¿¡´Â Á¦ÀÏ ¸¶Áö¸·¿¡
/// µé¾î¿Â ÀÚ½Ä ³ëµå¸¦ ¼±ÅÃÇÑ´Ù. ÇÏÁö¸¸ ¿©±â¼´Â Á¦ÀÏ Ã¹¹øÂ°·Î µé¾î¿Â ÀÚ½Ä
/// ³ëµå¸¦ ¼±ÅÃÇϰí, ±× ´ÙÀ½ µé¾î¿À´Â ³ëµå´Â »èÁ¦ÇØ ¹ö¸®´Â ¹æ½ÄÀ» ÅÃÇß´Ù.
/// ¹è¿ ÇüÅ·ΠÀÚ½ÄÀ» µÎ±â À§Çؼ´Â '-' ¿¬»êÀÚ¸¦ ÀÌ¿ëÇØ¾ß ÇÑ´Ù. ÀÚ¼¼ÇÑ °ÍÀº
/// ¿ª½Ã YAML ¹®¹ýÀ» Âü°í.
/// </summary>
/// <remarks>Verbatim 󸮰¡ ÇÊ¿äÇÏ´Ù.</remarks>
public class YamlTree
{
// ½ºÄ®¶óÀÇ Á¾·ù
public enum ScalarType
{
NORMAL, BLOCK, FOLDED
};
// Â÷ÀÏµå ³ëµå ÀúÀå ¹æ½Ä
public enum ChildType
{
MAPPED, SEQNENTIAL, UNKNOWN
};
// typedefs
public class Mapping :
System.Collections.Generic.Dictionary<string, YamlTree> {};
public class Sequence :
System.Collections.Generic.List<YamlTree> {};
public class Scalars :
System.Collections.Generic.List<string> {};
// instance variables
protected string m_Key = "";
protected string m_Value = "";
protected string m_Comment = "";
protected ScalarType m_ScalarType = ScalarType.NORMAL;
protected Scalars m_Scalars = new Scalars();
protected YamlTree m_Alias = null;
protected ChildType m_ChildType = ChildType.UNKNOWN;
protected Mapping m_MappedChilds = new Mapping();
protected Sequence m_SequentialChilds = new Sequence();
protected int m_MaxChildKeyLength = 0;
// properties
public string Key { get { return m_Key; } }
public string Value { get { return m_Value; } set { m_Value = value; } }
public YamlTree Alias { get { return m_Alias; } set { m_Alias = value; } }
public Mapping ChildAsMapping { get { return m_MappedChilds; } }
public Sequence ChildAsSequence { get { return m_SequentialChilds; } }
public int ChildCount { get { return m_SequentialChilds.Count; } }
// constructor
public YamlTree()
{
}
// constructor
public YamlTree(string key, object value)
{
m_Key = key;
m_Value = value.ToString();
}
// destructor
~YamlTree()
{
m_MappedChilds.Clear();
m_SequentialChilds.Clear();
}
// get node value
public string GetValueAsString() { return m_Value; }
public int GetValueAsInt() { return int.Parse(m_Value); }
public float GetValueAsFloat() { return float.Parse(m_Value); }
public double GetValueAsDouble() { return double.Parse(m_Value); }
public bool GetValueAsBoolean() { return bool.Parse(m_Value); }
// set node value
public void SetValue(string value) { m_Value = value; }
public void SetValue(int value) { m_Value = value.ToString(); }
public void SetValue(float value) { m_Value = value.ToString(); }
public void SetValue(double value) { m_Value = value.ToString(); }
public void SetValue(bool value) { m_Value = value.ToString(); }
// comment
public string GetComment()
{
return m_Alias == null ? m_Comment : m_Alias.GetComment();
}
public void SetComment(string comment)
{
if (m_Alias == null) { m_Comment = comment; }
else { m_Alias.SetComment(comment); }
}
// scalar
public ScalarType GetScalarType()
{
return m_Alias == null ? m_ScalarType : m_Alias.GetScalarType();
}
public void SetScalarType(ScalarType type)
{
if (m_Alias == null) { m_ScalarType = type; }
else { m_Alias.SetScalarType(type); }
}
public void AddScalar(string text)
{
if (m_Alias == null) { m_Scalars.Add(text); }
else { m_Alias.AddScalar(text); }
}
public Scalars GetScalars()
{
return m_Alias == null ? m_Scalars : m_Alias.GetScalars();
}
// ÀÚ½Ä ³ëµå¸¦ Ãß°¡ÇÑ´Ù.
public YamlTree AddChild(YamlTree child)
{
if (m_Alias != null)
throw new System.Exception("cannot add child to aliased node");
if (m_Value.Length > 0 && m_Value[0] != '&' && m_Value[0] != '*')
throw new System.Exception("cannot add child to scalar node");
if (child.Key == "")
{
if (m_ChildType == ChildType.UNKNOWN)
m_ChildType = ChildType.SEQNENTIAL;
if (m_ChildType != ChildType.SEQNENTIAL)
throw new System.Exception("cannot add sequencial node");
string buf = string.Format("{0,5:N}", m_SequentialChilds.Count);
m_SequentialChilds.Add(child);
m_MappedChilds.Add(buf.ToString(), child);
return child;
}
else
{
if (m_ChildType == ChildType.UNKNOWN)
m_ChildType = ChildType.MAPPED;
if (m_ChildType != ChildType.MAPPED)
throw new System.Exception("cannot add mapped node");
if (!m_MappedChilds.ContainsKey(child.Key.ToLower()))
{
m_MaxChildKeyLength =
System.Math.Max(m_MaxChildKeyLength, child.Key.Length);
m_MappedChilds.Add(child.Key.ToLower(), child);
m_SequentialChilds.Add(child);
return child;
}
else
{
throw new System.Exception(
string.Format("cannot add duplicated mapping - {0}", child.Key)
);
}
}
}
// ÀÚ½Ä ³ëµåÀÇ Á¸Àç ¿©ºÎ¸¦ üũÇÑ´Ù.
public bool HasChild(string key)
{
if (m_Alias != null) return m_Alias.HasChild(key);
if (m_ChildType == ChildType.MAPPED)
{
if (m_MappedChilds.ContainsKey(key.ToLower())) return true;
}
else if (m_ChildType == ChildType.SEQNENTIAL)
{
foreach (YamlTree child in m_SequentialChilds)
if (child.Key == key) return true;
}
return false;
}
// ÇØ´çÇÏ´Â ÀÚ½Ä ³ëµå¸¦ ¹ÝȯÇÑ´Ù.
public YamlTree GetChild(string key, bool strict)
{
if (m_Alias != null) return m_Alias.GetChild(key, strict);
if (m_ChildType == ChildType.MAPPED)
{
if (m_MappedChilds.ContainsKey(key.ToLower()))
return m_MappedChilds[key.ToLower()];
if (strict)
throw new System.Exception(
string.Format("cannot find specified child node {0} at {1}", key, m_Key)
);
return null;
}
else if (m_ChildType == ChildType.SEQNENTIAL)
{
foreach (YamlTree child in m_SequentialChilds)
if (child.Key == key) return child;
if (strict)
throw new System.Exception(
string.Format("cannot find specified child node {0} at {1}", key, m_Key)
);
return null;
}
if (strict)
throw new System.Exception(string.Format("{0} node has invalid child", m_Key));
return null;
}
// ÇØ´çÇÏ´Â ÀÚ½Ä ³ëµå¸¦ ¹ÝȯÇÑ´Ù.
public YamlTree GetChild(int i, bool strict)
{
if (m_Alias != null)
return m_Alias.GetChild(i, strict);
if (i < m_SequentialChilds.Count)
return m_SequentialChilds[i];
if (strict)
throw new System.Exception(
string.Format("out of range in node {0} with {1}", m_Key, i)
);
return null;
}
// ÀÚ½Ä ³ëµåÀÇ °ªÀ» ¼³Á¤ÇÑ´Ù.
public YamlTree AddAttr(string key, string value) { return AddChild(new YamlTree(key, value)); }
public YamlTree AddAttr(string key, int value) { return AddChild(new YamlTree(key, value)); }
public YamlTree AddAttr(string key, float value) { return AddChild(new YamlTree(key, value)); }
public YamlTree AddAttr(string key, double value) { return AddChild(new YamlTree(key, value)); }
public YamlTree AddAttr(string key, bool value) { return AddChild(new YamlTree(key, value)); }
// ÀÚ½Ä ³ëµåÀÇ °ªÀ» ¹ÝȯÇÑ´Ù.
public string AttrAsString(string key)
{
YamlTree child = GetChild(key, true);
return child != null ? child.GetValueAsString() : "";
}
public int AttrAsInt(string key)
{
YamlTree child = GetChild(key, true);
return child != null ? child.GetValueAsInt() : 0;
}
public float AttrAsFloat(string key)
{
YamlTree child = GetChild(key, true);
return child != null ? child.GetValueAsFloat() : 0.0f;
}
public double AttrAsDouble(string key)
{
YamlTree child = GetChild(key, true);
return child != null ? child.GetValueAsFloat() : 0.0;
}
public bool AttrAsBool(string key)
{
YamlTree child = GetChild(key, true);
return child != null ? child.GetValueAsBoolean() : false;
}
// ÀÚ½Ä ³ëµåÀÇ °ªÀ» ¾ÈÀüÇϰÔ(-_-) ¹ÝȯÇÑ´Ù.
public string AttrAsStringSafe(string key, string nullValue)
{
YamlTree child = GetChild(key, false);
return child != null ? child.GetValueAsString() : nullValue;
}
public int AttrAsIntSafe(string key, int nullValue)
{
YamlTree child = GetChild(key, false);
return child != null ? child.GetValueAsInt() : nullValue;
}
public float AttrAsFloatSafe(string key, float nullValue)
{
YamlTree child = GetChild(key, false);
return child != null ? child.GetValueAsFloat() : nullValue;
}
public double AttrAsDoubleSafe(string key, double nullValue)
{
YamlTree child = GetChild(key, false);
return child != null ? child.GetValueAsFloat() : nullValue;
}
public bool AttrAsBoolSafe(string key, bool nullValue)
{
YamlTree child = GetChild(key, false);
return child != null ? child.GetValueAsBoolean() : nullValue;
}
// ¹®ÀÚ¿ÈÇÑ´Ù.
public override string ToString()
{
System.Text.StringBuilder msg = new System.Text.StringBuilder();
if (m_Comment.Length > 0)
msg.AppendFormat("{0}\n", m_Comment);
bool mapped = m_ChildType == ChildType.MAPPED;
foreach (YamlTree child in m_SequentialChilds)
{
string result = child.ToString(0, mapped, "", m_MaxChildKeyLength);
msg.AppendFormat("{0}", result);
}
return msg.ToString();
}
// ¹®ÀÚ¿ÈÇÑ´Ù.
private string ToString(int indent, bool mapped, string header, int maxKeyLength)
{
System.Text.StringBuilder msg = new System.Text.StringBuilder();
string spaces = "";
for (int i=0; i<indent; ++i)
spaces = spaces + " ";
if (m_Comment.Length > 0)
{
string comment = m_Comment;
comment = comment.Replace("\n", "\n" + spaces);
string trimmed = comment.Trim();
if (trimmed.Length > 0 && trimmed[trimmed.Length-1] == '\n')
msg.AppendFormat("{0}{1}", spaces, comment);
else
msg.AppendFormat("{0}{1}\n", spaces, comment);
}
if (mapped)
{
msg.AppendFormat("{0}{1}{2}:", spaces, header, m_Key);
string value = m_Value;
switch (m_ScalarType)
{
case ScalarType.NORMAL:
msg.AppendFormat(" {0}\n", value);
break;
case ScalarType.BLOCK:
msg.AppendFormat(" |\n");
foreach (string text in m_Scalars)
msg.AppendFormat("{0} {1}\n", spaces, text);
break;
case ScalarType.FOLDED:
msg.AppendFormat(" >\n");
foreach (string text in m_Scalars)
msg.AppendFormat("{0} {1}\n", spaces, text);
break;
default:
msg.AppendFormat("{0}{1}: {2}\n", spaces, m_Key, value);
break;
}
if (m_ChildType == ChildType.MAPPED)
{
foreach (YamlTree child in m_SequentialChilds)
{
if (header.Length == 0)
msg.Append(child.ToString(indent + 2, true, "", m_MaxChildKeyLength));
else
msg.Append(child.ToString(indent + 3, true, "", m_MaxChildKeyLength));
}
}
else if (m_ChildType == ChildType.SEQNENTIAL)
{
foreach (YamlTree child in m_SequentialChilds)
{
msg.Append(child.ToString(indent + 1, false, "", m_MaxChildKeyLength));
}
}
}
else
{
bool first = true;
bool childMapped = m_ChildType == ChildType.MAPPED;
foreach (YamlTree child in m_SequentialChilds)
{
if (first)
{
msg.Append(child.ToString(indent, childMapped, "- ", m_MaxChildKeyLength));
first = false;
}
else
{
msg.Append(child.ToString(indent + 1, childMapped, "", m_MaxChildKeyLength));
}
}
}
return msg.ToString();
}
// ¸ðµç ³ëµå »èÁ¦
public void Clear()
{
if (m_SequentialChilds.Count != m_MappedChilds.Count)
throw new System.Exception(
string.Format("child count mismatch at node {0}", m_Key)
);
m_Key = "";
m_Value = "";
m_Comment = "";
m_ScalarType = ScalarType.NORMAL;
m_Scalars.Clear();
m_Alias = null;
m_ChildType = ChildType.UNKNOWN;
m_MappedChilds.Clear();
m_SequentialChilds.Clear();
m_MaxChildKeyLength = 0;
}
}
// ÆÄ½Ì Áß¿¡ ³»ºÎÀûÀ¸·Î »ç¿ëÇϱâ À§ÇÑ ±¸Á¶Ã¼
internal struct STATE
{
public YamlTree node;
public int indent;
public STATE(YamlTree n, int i) { node = n; indent = i; }
};
// À§¿¡¼ ¼±¾ðÇÑ ±¸Á¶Ã¼¸¦ ÀÌ¿ëÇÑ ½ºÅÃ
internal class StateStack : System.Collections.Generic.Stack<STATE> { };
/// <summary>
/// Çü½ÄÈµÈ ÆÄÀÏ ÀÔÃâ·ÂÀ» À§ÇÑ ½ºÆ®¸² °´Ã¼. ¶óÀÎ ´ÜÀ§·Î ÆÄÀÏÀ» ÀоîµéÀÌ´Â
/// ±â´É ¿Ü¿¡ ¸¶Áö¸·À¸·Î ÀоîµéÀÎ ¹®ÀÚ¿À» ÀÌ¿ëÇØ ´ÙÀ½ ¶óÀÎÀ» ¾î¶»°Ô
/// ó¸®ÇÏ´À³Ä¸¦ ÆÇ´ÜÇÏ´Â ±â´Éµµ ´ã´çÇÑ´Ù.
/// </summary>
internal class YamlStream
{
// »ó¼öµé
private const string YAML_WHITESPACES = " \t\r\n";
private const string YAML_LINEFEEDS = "\r\n";
private const string YAML_INDENT = " \t";
private const char YAML_COLON = ':';
private const char YAML_SHARP = '#';
private const char YAML_MINUS = '-';
private const char YAML_AMPERSAND = '&';
private const char YAML_ASTERISK = '*';
private const string YAML_PIPE = "|";
private const string YAML_RIGHT_BRACKET = ">";
private const string YAML_DOCUMENT_HEADER = "---";
private const string YAML_DOCUMENT_TERMINATOR = "...";
// ÆÄ½Ì °á°ú
public enum ParseResult { NORMAL, EMPTY };
// ÇöÀç ÆÄ½Ì ¸ðµå
public enum ParseMode { NORMAL, BLOCK, FOLDED };
// ÇöÀç Àε§Æ® °ªÀ» ±âÁØÀ¸·Î ½ºÅÿ¡¼ Á¤È®ÇÑ ºÎ¸ð¸¦ ã¾Æ, ÁÖ¾îÁø ³ëµå¸¦
// ÀÚ½Ä ³ëµå·Î ÆíÀÔ½ÃŲ´Ù.
public static YamlTree AdoptChild(StateStack stack, int indent, YamlTree child)
{
while (stack.Count > 0)
{
STATE e = stack.Peek();
if (e.indent == indent)
return e.node.AddChild(child);
else
stack.Pop();
}
return null;
}
// C++ STL string::find_first_not_of
public static int IndexNotOf(string text, string delimiters, int startIndex)
{
int index = startIndex;
while (index < text.Length)
{
if (delimiters.IndexOf(text[index]) == -1)
return index;
index++;
}
return -1;
}
// C++ STL string::find_last_not_of
public static int LastIndexNotOf(string text, string delimiters, int startIndex)
{
int index = startIndex;
int foundIdx = -1;
while (index < text.Length)
{
if (delimiters.IndexOf(text[index]) == -1)
foundIdx = index;
index++;
}
return foundIdx;
}
// instance variables
System.IO.StreamReader m_File = null;
YamlDocument m_Document = null;
int m_Line = 0;
int m_Indent = 0;
string m_Text = "";
string m_Comment = "";
ParseMode m_Mode = ParseMode.NORMAL;
// properties
public ParseMode Mode { get { return m_Mode; } }
public int Line { get { return m_Line; } }
public int Indent { get { return m_Indent; } }
public string Text { get { return m_Text; } }
// costructor
public YamlStream(string fileName, YamlDocument document)
{
m_File = new System.IO.StreamReader(fileName, document.Encoding);
m_Document = document;
}
// ÇÑ ¶óÀÎÀ» Àоîµé¿© ÆÄ½ÌÇÑ´Ù.
public ParseResult ParseNextLine(bool processComment)
{
++m_Line;
m_Text = m_File.ReadLine();
if (m_Text.Length == 0)
return ParseResult.EMPTY; // empty line
int pos = IndexNotOf(m_Text, YAML_INDENT, 0);
if (pos < 0)
{
m_Comment += "\n";
return ParseResult.EMPTY; // only whitespace
}
if (processComment && m_Text[pos] == YAML_SHARP)
{
m_Comment += m_Text.Substring(pos) + "\n";
return ParseResult.EMPTY; // comment line
}
m_Indent = pos;
return ParseResult.NORMAL;
}
// ÇöÀç ¶óÀÎÀÇ ÅØ½ºÆ®¸¦ ÀÌ¿ëÇØ Æ®¸® °´Ã¼¸¦ »ý¼ºÇÑ´Ù.
public YamlTree CreateTree()
{
string text = m_Text;
int pos = text.IndexOf(YAML_COLON);
if (pos < 0)
throw new System.Exception("cannot find colon character");
string key = text.Substring(0, pos).Trim();
string value = text.Substring(pos + 1).Trim();
if (key.Length == 0)
throw new System.Exception("key text is empty");
YamlTree result = null;
if (key[0] == YAML_MINUS)
{
m_Indent += IndexNotOf(key, YAML_INDENT, 1);
key = key.Substring(1).Trim();
result = new YamlTree("", "");
result.AddChild(new YamlTree(key, value));
}
else
{
result = new YamlTree(key, value);
}
if (m_Comment.Length > 0)
{
result.SetComment(m_Comment.Substring(0, m_Comment.Length - 1));
m_Comment = "";
}
if (value.Length > 1)
{
if (value[0] == YAML_AMPERSAND)
{
m_Document.AddAnchor(value.Substring(1).Trim(), result);
}
else if (value[0] == YAML_ASTERISK)
{
string trimmed = value.Substring(1);
YamlTree anchor = m_Document.GetAnchor(trimmed);
if (anchor == null)
throw new System.Exception("no such anchor " + trimmed);
result.Alias = anchor;
}
}
if (value == YAML_PIPE)
{
m_Mode = ParseMode.BLOCK;
result.SetValue("");
}
else if (value == YAML_RIGHT_BRACKET)
{
m_Mode = ParseMode.FOLDED;
result.SetValue("");
}
else
{
m_Mode = ParseMode.NORMAL;
}
return result;
}
// ½ºÆ®¸²ÀÇ »óŰ¡ Á¤»óÀûÀΰ¡ÀÇ ¿©ºÎ
public bool IsGood() { return m_File.EndOfStream == false; }
// ÇöÀç ¶óÀÎÀÌ ºó ¶óÀÎÀÎÁöÀÇ ¿©ºÎ
public bool IsEmptyLine()
{
string trimmed = m_Text.Trim();
return trimmed.Length == 0 || trimmed[0] == YAML_SHARP;
}
};
/// <summary>
/// YamlTree ÃÖ»óÀ§ ³ëµå.
///
/// ½ÇÁ¦·Î ÆÄÀÏ ÀÔÃâ·ÂÀ» ´Ù·ê ¶§¿¡´Â ÀÌ Å¬·¡½º¸¦ ÀÌ¿ëÇØ¾ß ÇÑ´Ù. ÀÌ¿Í °°Àº
/// Ŭ·¡½º°¡ ÇÊ¿äÇÑ ÀÌÀ¯´Â ANCHOR Á¤º¸°¡ ¹®¼ Àüü¸¦ ÅëÇØ Àü¿ªÀ¸·Î Á¸ÀçÇϱâ
/// ¶§¹®ÀÌ´Ù. Load/Save ÇÔ¼öµµ ¾îÂ÷ÇÇ ÀÌ¿Í °°Àº Ŭ·¡½º¸¦ µû·Î µÎ°í, ÀÌ ¾È¿¡
/// ³Ö´Â °ÍÀÌ ±ò²ûÇϱâ´Â ÇÏ´Ù.
///
/// Anchor & alias °°Àº °æ¿ì, ÆÄÀÏÀ» ÀоîµéÀÏ ¶§, Áï ÀÌ¹Ì Á¸ÀçÇÏ´Â
/// anchor & alias Á¤º¸¸¦ ÀоîµéÀÌ´Â °ÍÀº º° ¹®Á¦°¡ ¾ø´Ù. ¹®Á¦´Â ±× ¹Ý´ë,
/// Áï ¸Þ¸ð¸® »ó¿¡¼ Æ®¸® ±¸Á¶¸¦ ±¸¼ºÇÑ ÈÄ, ÆÄÀÏ¿¡´Ù ¾µ ¶§´Â ÀÎÅÍÆäÀ̽º¸¦
/// ¾î¶»°Ô Á¦°øÇØ¾ß ÇÒÁö¸¦ Àß ¸ð¸£°Ú´Ù.
/// </summary>
public class YamlDocument : YamlTree
{
// typedef
class Anchors :
System.Collections.Generic.Dictionary<string,YamlTree> {};
// instance variables
System.Text.Encoding m_Encoding = null;
Anchors m_Anchors = new Anchors();
string m_LastError = "";
// properties
public System.Text.Encoding Encoding { get { return m_Encoding; } set { m_Encoding = value; } }
public string LastError { get { return m_LastError; } }
// anchors
public void AddAnchor(string name, YamlTree tree)
{
m_Anchors.Add(name.ToLower(), tree);
}
public YamlTree GetAnchor(string name)
{
return m_Anchors.ContainsKey(name.ToLower()) ? m_Anchors[name.ToLower()] : null;
}
public void ClearAnchors()
{
m_Anchors.Clear();
}
// »ý¼ºÀÚ
public YamlDocument()
: base()
{
m_Key = "<ROOT>";
m_Encoding = System.Text.Encoding.Default;
}
// »ý¼ºÀÚ
public YamlDocument(System.Text.Encoding encoding)
: base()
{
m_Key = "<ROOT>";
m_Encoding = encoding;
}
// ºÒ·¯¿À±â
public bool Load(string fileName)
{
Clear();
ClearAnchors();
YamlStream stream = new YamlStream(fileName, this);
if (!stream.IsGood())
{
m_LastError = "cannot open " + fileName;
return false;
}
StateStack stack = new StateStack();
stack.Push(new STATE(this, -1));
bool result = true;
YamlStream.ParseMode mode = YamlStream.ParseMode.NORMAL;
YamlTree lastChild = null;
try
{
while (stream.IsGood())
{
if (stack.Count == 0)
throw new System.Exception("indent error");
bool normal = mode == YamlStream.ParseMode.NORMAL;
if (stream.ParseNextLine(normal) != YamlStream.ParseResult.NORMAL)
continue;
int indent = stream.Indent;
STATE top = stack.Peek();
if (top.indent == -1)
{
stack.Pop();
stack.Push(new STATE(top.node, indent));
top = stack.Peek();
}
if (mode == YamlStream.ParseMode.NORMAL)
{
if (top.indent == indent)
{
if (top.node.Alias != null)
throw new System.Exception(
"cannot add child node to aliased node " + top.node.Key
);
YamlTree child = stream.CreateTree();
if (child.ChildCount == 0 || child.Alias != null)
{
lastChild = top.node.AddChild(child);
}
else
{
top.node.AddChild(child);
stack.Push(new STATE(child, stream.Indent));
lastChild = child.GetChild(0, true);
}
}
else if (top.indent < indent)
{
if (lastChild == null)
throw new System.Exception("indent error");
if (lastChild.Alias != null)
throw new System.Exception(
"cannot add child node to aliased node " + lastChild.Key
);
stack.Push(new STATE(lastChild, indent));
YamlTree child = stream.CreateTree();
if (child.ChildCount == 0 || child.Alias != null)
{
lastChild = lastChild.AddChild(child);
}
else
{
stack.Push(new STATE(child, stream.Indent));
lastChild.AddChild(child);
lastChild = child.GetChild(0, true);
}
}
else if (indent < top.indent)
{
YamlTree child = stream.CreateTree();
if (child.ChildCount == 0 || child.Alias != null)
{
lastChild = YamlStream.AdoptChild(stack, indent, child);
}
else
{
YamlStream.AdoptChild(stack, indent, child);
stack.Push(new STATE(child, stream.Indent));
lastChild = child.GetChild(0, true);
}
}
mode = stream.Mode;
}
else
{
if (top.indent == indent)
{
if (stream.IsEmptyLine()) continue;
YamlTree child = stream.CreateTree();
lastChild = top.node.AddChild(child);
mode = stream.Mode;
}
else if (top.indent < indent)
{
string trimmed = stream.Text.Trim();
if (mode == YamlStream.ParseMode.BLOCK)
{
lastChild.SetValue(lastChild.GetValueAsString() + "\n" + trimmed);
lastChild.SetScalarType(YamlTree.ScalarType.BLOCK);
lastChild.AddScalar(trimmed);
}
else if (mode == YamlStream.ParseMode.FOLDED)
{
lastChild.SetValue(lastChild.GetValueAsString() + " " + trimmed);
lastChild.SetScalarType(YamlTree.ScalarType.FOLDED);
lastChild.AddScalar(trimmed);
}
}
else if (indent < top.indent)
{
if (stream.IsEmptyLine()) continue;
lastChild = YamlStream.AdoptChild(stack, indent, stream.CreateTree());
mode = stream.Mode;
}
}
}
}
catch (System.Exception e)
{
m_LastError = string.Format("{0}:{1} {2}", fileName, stream.Line, e.ToString());
result = false;
}
return result;
}
// ÀúÀå
public bool Save(string fileName)
{
System.IO.StreamWriter file = new System.IO.StreamWriter(fileName, false, m_Encoding);
string msg = ToString();
file.WriteLine(msg);
file.Close();
return true;
}
};
}
SeriousMoin v1 (koMoinMoin 1.0a4 Modified)