You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
10 KiB
316 lines
10 KiB
//
|
|
// NodeGroup.cs
|
|
//
|
|
// Author: Kees van Spelde <sicos2002@hotmail.com>
|
|
//
|
|
// Copyright (c) 2013-2018 Magic-Sessions. (www.magic-sessions.com)
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.Text;
|
|
|
|
namespace MsgReader.Rtf
|
|
{
|
|
/// <summary>
|
|
/// RTF node group
|
|
/// </summary>
|
|
internal class NodeGroup : Node
|
|
{
|
|
#region Fields
|
|
/// <summary>
|
|
/// child node list
|
|
/// </summary>
|
|
protected NodeList InternalNodes = new NodeList();
|
|
#endregion
|
|
|
|
#region Constructor
|
|
/// <summary>
|
|
/// initialize instance
|
|
/// </summary>
|
|
public NodeGroup()
|
|
{
|
|
Type = RtfNodeType.Group;
|
|
}
|
|
#endregion
|
|
|
|
#region Properties
|
|
/// <summary>
|
|
/// child node list
|
|
/// </summary>
|
|
public override NodeList Nodes => InternalNodes;
|
|
|
|
/// <summary>
|
|
/// first child node
|
|
/// </summary>
|
|
public Node FirstNode => InternalNodes.Count > 0 ? InternalNodes[0] : null;
|
|
|
|
public override string Keyword => InternalNodes.Count > 0 ? InternalNodes[0].Keyword : null;
|
|
|
|
public override bool HasParameter => InternalNodes.Count > 0 && InternalNodes[0].HasParameter;
|
|
|
|
public override int Parameter => InternalNodes.Count > 0 ? InternalNodes[0].Parameter : 0;
|
|
|
|
|
|
public virtual string Text
|
|
{
|
|
get
|
|
{
|
|
var stringBuilder = new StringBuilder();
|
|
foreach (Node node in InternalNodes)
|
|
{
|
|
if (node is NodeGroup)
|
|
stringBuilder.Append(((NodeGroup) node).Text);
|
|
if (node.Type == RtfNodeType.Text)
|
|
stringBuilder.Append(node.Keyword);
|
|
}
|
|
return stringBuilder.ToString();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region GetAllNodes
|
|
/// <summary>
|
|
/// Get all child node deeply
|
|
/// </summary>
|
|
/// <param name="includeGroupNode">contains group type node</param>
|
|
/// <returns>child nodes list</returns>
|
|
public NodeList GetAllNodes(bool includeGroupNode)
|
|
{
|
|
var nodeList = new NodeList();
|
|
AddAllNodes(nodeList, includeGroupNode);
|
|
return nodeList;
|
|
}
|
|
#endregion
|
|
|
|
#region AddAllNodes
|
|
private void AddAllNodes(NodeList nodeList, bool includeGroupNode)
|
|
{
|
|
foreach (Node node in InternalNodes)
|
|
{
|
|
if (node is NodeGroup)
|
|
{
|
|
if (includeGroupNode)
|
|
nodeList.Add(node);
|
|
((NodeGroup) node).AddAllNodes(nodeList, includeGroupNode);
|
|
}
|
|
else
|
|
nodeList.Add(node);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region MergeText
|
|
internal void MergeText()
|
|
{
|
|
var nodeList = new NodeList();
|
|
var stringBuilder = new StringBuilder();
|
|
var byteBuffer = new ByteBuffer();
|
|
|
|
foreach (Node node in InternalNodes)
|
|
{
|
|
if (node.Type == RtfNodeType.Text)
|
|
{
|
|
AddString(stringBuilder, byteBuffer);
|
|
stringBuilder.Append(node.Keyword);
|
|
continue;
|
|
}
|
|
|
|
if (node.Type == RtfNodeType.Control
|
|
&& node.Keyword == "\'"
|
|
&& node.HasParameter)
|
|
{
|
|
byteBuffer.Add((byte) node.Parameter);
|
|
continue;
|
|
}
|
|
|
|
if (node.Type == RtfNodeType.Control || node.Type == RtfNodeType.Keyword)
|
|
{
|
|
if (node.Keyword == "tab")
|
|
{
|
|
AddString(stringBuilder, byteBuffer);
|
|
stringBuilder.Append('\t');
|
|
continue;
|
|
}
|
|
if (node.Keyword == "emdash")
|
|
{
|
|
AddString(stringBuilder, byteBuffer);
|
|
stringBuilder.Append('-');
|
|
continue;
|
|
}
|
|
if (node.Keyword == string.Empty)
|
|
{
|
|
AddString(stringBuilder, byteBuffer);
|
|
stringBuilder.Append('-');
|
|
continue;
|
|
}
|
|
}
|
|
|
|
AddString(stringBuilder, byteBuffer);
|
|
|
|
if (stringBuilder.Length > 0)
|
|
{
|
|
nodeList.Add(new Node(RtfNodeType.Text, stringBuilder.ToString()));
|
|
stringBuilder = new StringBuilder();
|
|
}
|
|
nodeList.Add(node);
|
|
}
|
|
|
|
AddString(stringBuilder, byteBuffer);
|
|
|
|
if (stringBuilder.Length > 0)
|
|
nodeList.Add(new Node(RtfNodeType.Text, stringBuilder.ToString()));
|
|
|
|
InternalNodes.Clear();
|
|
|
|
foreach (Node node in nodeList)
|
|
{
|
|
node.Parent = this;
|
|
node.OwnerDocument = InternalOwnerDocument;
|
|
InternalNodes.Add(node);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region AddString
|
|
private void AddString(StringBuilder stringBuilder, ByteBuffer buffer)
|
|
{
|
|
if (buffer.Count > 0)
|
|
{
|
|
var text = buffer.GetString(InternalOwnerDocument.RuntimeEncoding);
|
|
stringBuilder.Append(text);
|
|
buffer.Reset();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Write
|
|
/// <summary>
|
|
/// Write content to rtf document
|
|
/// </summary>
|
|
/// <param name="writer">RTF text writer</param>
|
|
public override void Write(Writer writer)
|
|
{
|
|
writer.WriteStartGroup();
|
|
|
|
foreach (Node node in InternalNodes)
|
|
node.Write(writer);
|
|
|
|
writer.WriteEndGroup();
|
|
}
|
|
#endregion
|
|
|
|
#region SearchKey
|
|
/// <summary>
|
|
/// Search child node with special keyword
|
|
/// </summary>
|
|
/// <param name="key">Special keyword</param>
|
|
/// <param name="deeply">Whether search deeply</param>
|
|
/// <returns>Found node</returns>
|
|
public Node SearchKey(string key, bool deeply)
|
|
{
|
|
foreach (Node node in InternalNodes)
|
|
{
|
|
if (node.Type == RtfNodeType.Keyword
|
|
|| node.Type == RtfNodeType.ExtKeyword
|
|
|| node.Type == RtfNodeType.Control)
|
|
{
|
|
if (node.Keyword == key)
|
|
return node;
|
|
}
|
|
|
|
if (deeply)
|
|
{
|
|
if (node is NodeGroup)
|
|
{
|
|
var groupNode = (NodeGroup) node;
|
|
var n = groupNode.SearchKey(key, true);
|
|
if (n != null)
|
|
return n;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
#endregion
|
|
|
|
#region AppendChild
|
|
/// <summary>
|
|
/// Append child node
|
|
/// </summary>
|
|
/// <param name="node">node</param>
|
|
public void AppendChild(Node node)
|
|
{
|
|
CheckNodes();
|
|
if (node == null)
|
|
throw new ArgumentNullException(nameof(node));
|
|
if (node == this)
|
|
throw new ArgumentException("node != this");
|
|
node.Parent = this;
|
|
node.OwnerDocument = InternalOwnerDocument;
|
|
Nodes.Add(node);
|
|
}
|
|
#endregion
|
|
|
|
#region RemoveChild
|
|
/// <summary>
|
|
/// Remove child
|
|
/// </summary>
|
|
/// <param name="node">node</param>
|
|
public void RemoveChild(Node node)
|
|
{
|
|
CheckNodes();
|
|
if (node == null)
|
|
throw new ArgumentNullException(nameof(node));
|
|
if (node == this)
|
|
throw new ArgumentException("node != this");
|
|
Nodes.Remove(node);
|
|
}
|
|
#endregion
|
|
|
|
#region InsertNode
|
|
/// <summary>
|
|
/// Insert node
|
|
/// </summary>
|
|
/// <param name="index">index</param>
|
|
/// <param name="node">node</param>
|
|
public void InsertNode(int index, Node node)
|
|
{
|
|
CheckNodes();
|
|
if (node == null)
|
|
throw new ArgumentNullException(nameof(node));
|
|
if (node == this)
|
|
throw new ArgumentException("node != this");
|
|
|
|
node.Parent = this;
|
|
node.OwnerDocument = InternalOwnerDocument;
|
|
Nodes.Insert(index, node);
|
|
}
|
|
#endregion
|
|
|
|
#region CheckNodes
|
|
private void CheckNodes()
|
|
{
|
|
if (Nodes == null)
|
|
throw new Exception("Child node is invalid");
|
|
}
|
|
#endregion
|
|
}
|
|
} |