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.

467 lines
15 KiB

//
// RawDocument.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.Collections;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
namespace MsgReader.Rtf
{
/// <summary>
/// RTF raw document
/// </summary>
internal class RawDocument : NodeGroup
{
#region Fields
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable FieldCanBeMadeReadOnly.Global
/// <summary>
/// Text encoding for current associated font
/// </summary>
private Encoding _associatedFontChartset;
/// <summary>
/// Color table
/// </summary>
protected ColorTable InternalColorTable = new ColorTable();
private Encoding _encoding;
/// <summary>
/// Text encoding for current font
/// </summary>
private Encoding _fontChartset;
/// <summary>
/// font table
/// </summary>
protected Table InternalFontTable = new Table();
/// <summary>
/// document information
/// </summary>
protected DocumentInfo InternalInfo = new DocumentInfo();
// ReSharper restore FieldCanBeMadeReadOnly.Global
#endregion
#region Properties
/// <summary>
/// The owner of this document
/// </summary>
public override RawDocument OwnerDocument
{
get { return this; }
set { }
}
/// <summary>
/// No parent node
/// </summary>
public override NodeGroup Parent
{
get { return null; }
set { }
}
/// <summary>
/// color table
/// </summary>
public ColorTable ColorTable => InternalColorTable;
/// <summary>
/// font table
/// </summary>
public Table FontTable => InternalFontTable;
/// <summary>
/// Document information
/// </summary>
public DocumentInfo Info => InternalInfo;
/// <summary>
/// Text encoding
/// </summary>
public Encoding Encoding
{
get
{
if (_encoding == null)
{
var node = InternalNodes[Consts.Ansicpg];
if (node != null && node.HasParameter)
_encoding = Encoding.GetEncoding(node.Parameter);
}
return _encoding ?? (_encoding = Encoding.Default);
}
}
/// <summary>
/// Current text encoding
/// </summary>
internal Encoding RuntimeEncoding
{
get
{
if (_fontChartset != null)
return _fontChartset;
return _associatedFontChartset ?? Encoding;
}
}
// ReSharper restore MemberCanBePrivate.Global
#endregion
#region Constructor
/// <summary>
/// Initialize instance
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public RawDocument()
{
InternalOwnerDocument = this;
// ReSharper disable once DoNotCallOverridableMethodsInConstructor
Parent = null;
InternalColorTable.CheckValueExistWhenAdd = false;
}
#endregion
#region ReadFontTable
/// <summary>
/// Read font table
/// </summary>
/// <param name="group"></param>
private void ReadFontTable(NodeGroup group)
{
InternalFontTable.Clear();
foreach (Node node in group.Nodes)
{
if (node is NodeGroup)
{
var index = -1;
string name = null;
var charset = 0;
foreach (Node item in node.Nodes)
{
if (item.Keyword == "f" && item.HasParameter)
index = item.Parameter;
else if (item.Keyword == Consts.Fcharset)
charset = item.Parameter;
else if (item.Type == RtfNodeType.Text)
{
if (!string.IsNullOrEmpty(item.Keyword))
{
name = item.Keyword;
break;
}
}
}
if (index >= 0 && name != null)
{
if (name.EndsWith(";"))
name = name.Substring(0, name.Length - 1);
name = name.Trim();
//System.Console.WriteLine( "Index:" + index + " Name:" + name );
var font = new Font(index, name) {Charset = charset};
InternalFontTable.Add(font);
}
}
}
}
#endregion
#region ReadColorTable
/// <summary>
/// Read color table
/// </summary>
/// <param name="group"></param>
private void ReadColorTable(NodeGroup group)
{
InternalColorTable.Clear();
var r = -1;
var g = -1;
var b = -1;
foreach (Node node in group.Nodes)
{
if (node.Keyword == "red")
r = node.Parameter;
else if (node.Keyword == "green")
g = node.Parameter;
else if (node.Keyword == "blue")
b = node.Parameter;
if (node.Keyword == ";")
{
if (r >= 0 && g >= 0 && b >= 0)
{
var c = Color.FromArgb(255, r, g, b);
InternalColorTable.Add(c);
r = -1;
g = -1;
b = -1;
}
}
}
if (r >= 0 && g >= 0 && b >= 0)
{
// Read the last color
var c = Color.FromArgb(255, r, g, b);
InternalColorTable.Add(c);
}
}
#endregion
#region ReadDocumentInfo
/// <summary>
/// Read document information
/// </summary>
/// <param name="group"></param>
private void ReadDocumentInfo(NodeGroup group)
{
InternalInfo.Clear();
//var nodeList = group.GetAllNodes(false);
foreach (Node node in group.Nodes)
{
if ((node is NodeGroup) == false)
continue;
if (node.Keyword == "creatim")
InternalInfo.CreationTime = ReadDateTime(node);
else if (node.Keyword == "revtim")
InternalInfo.RevisionTime = ReadDateTime(node);
else if (node.Keyword == "printim")
InternalInfo.PrintTime = ReadDateTime(node);
else if (node.Keyword == "buptim")
InternalInfo.BackupTime = ReadDateTime(node);
else
InternalInfo.SetInfo(node.Keyword, node.HasParameter ? node.Parameter.ToString(CultureInfo.InvariantCulture) : node.Nodes.Text);
}
}
#endregion
#region ReadDateTime
/// <summary>
/// Read date and time from node
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
private DateTime ReadDateTime(Node node)
{
var yr = node.Nodes.GetParameter("yr", 1900);
var mo = node.Nodes.GetParameter("mo", 1);
var dy = node.Nodes.GetParameter("dy", 1);
var hr = node.Nodes.GetParameter("hr", 0);
var min = node.Nodes.GetParameter("min", 0);
var sec = node.Nodes.GetParameter("sec", 0);
return new DateTime(yr, mo, dy, hr, min, sec);
}
#endregion
#region Load
/// <summary>
/// Load rtf from string
/// </summary>
/// <param name="text">Text in rtf format</param>
// ReSharper disable once UnusedMember.Global
public void LoadRtfText(string text)
{
_encoding = null;
using (var reader = new Reader())
{
if (reader.LoadRtfText(text))
Load(reader);
}
}
/// <summary>
/// Load rtf from file
/// </summary>
/// <param name="fileName">file name</param>
// ReSharper disable once UnusedMember.Global
public void Load(string fileName)
{
_encoding = null;
using (var reader = new Reader())
{
if (reader.LoadRtfFile(fileName))
Load(reader);
}
}
/// <summary>
/// Load rtf from text reader
/// </summary>
/// <param name="reader"></param>
public void Load(TextReader reader)
{
var rdr = new Reader();
rdr.LoadReader(reader);
Load(rdr);
}
/// <summary>
/// Load rtf from rtf reader
/// </summary>
/// <param name="reader">RTF text reader</param>
// ReSharper disable once MemberCanBePrivate.Global
public void Load(Reader reader)
{
InternalNodes.Clear();
var groups = new Stack();
NodeGroup newGroup = null;
while (reader.ReadToken() != null)
{
if (reader.TokenType == RtfTokenType.GroupStart)
{
// Begin group
if (newGroup == null)
newGroup = this;
else
{
newGroup = new NodeGroup {OwnerDocument = this};
}
if (newGroup != this)
{
var group = (NodeGroup) groups.Peek();
group.AppendChild(newGroup);
}
groups.Push(newGroup);
}
else if (reader.TokenType == RtfTokenType.GroupEnd)
{
// end group
newGroup = (NodeGroup) groups.Pop();
newGroup.MergeText();
// ReSharper disable once CSharpWarnings::CS0183
if (newGroup.FirstNode is Node)
{
switch (newGroup.Keyword)
{
case Consts.Fonttbl:
// Read font table
ReadFontTable(newGroup);
break;
case Consts.Colortbl:
// Read color table
ReadColorTable(newGroup);
break;
case Consts.Info:
// Read document information
ReadDocumentInfo(newGroup);
break;
}
}
if (groups.Count > 0)
newGroup = (NodeGroup) groups.Peek();
else
break;
//NewGroup.MergeText();
}
else
{
// Read content
var newNode = new Node(reader.CurrentToken) {OwnerDocument = this};
if (newGroup != null) newGroup.AppendChild(newNode);
switch (newNode.Keyword)
{
case Consts.F:
{
var font = FontTable[newNode.Parameter];
_fontChartset = font != null ? font.Encoding : null;
//myFontChartset = RTFFont.GetRTFEncoding( NewNode.Parameter );
}
break;
case Consts.Af:
{
var font = FontTable[newNode.Parameter];
_associatedFontChartset = font != null ? font.Encoding : null;
}
break;
}
}
}
while (groups.Count > 0)
{
newGroup = (NodeGroup) groups.Pop();
newGroup.MergeText();
}
//this.UpdateInformation();
}
#endregion
#region Write
/// <summary>
/// Write rtf
/// </summary>
/// <param name="writer">RTF writer</param>
public override void Write(Writer writer)
{
writer.Encoding = Encoding;
base.Write(writer);
}
#endregion
#region Save
/// <summary>
/// Save rtf to a file
/// </summary>
/// <param name="fileName">file name</param>
public void Save(string fileName)
{
using (var writer = new Writer(fileName))
Write(writer);
}
/// <summary>
/// Save rtf to a stream
/// </summary>
/// <param name="stream">stream</param>
public void Save(Stream stream)
{
using (var writer = new Writer(new StreamWriter(stream, Encoding)))
Write(writer);
}
#endregion
}
}