728x90
반응형
728x170
■ RTF 파서를 사용해 RTF 문서 구조를 파싱하는 방법을 보여준다.
[TestLibrary 프로젝트]
▶ ANSIEncoding.cs
using System;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// ANSI 인코딩
/// </summary>
internal class ANSIEncoding : Encoding
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 인스턴스
/// </summary>
public static ANSIEncoding Instance = new ANSIEncoding();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - GetString(byteArray, index, count)
/// <summary>
/// 문자열 구하기
/// </summary>
/// <param name="byteArray">바이트 배열</param>
/// <param name="index">인덱스</param>
/// <param name="count">카운트</param>
/// <returns>문자열</returns>
public override string GetString(byte[] byteArray, int index, int count)
{
StringBuilder stringBuilder = new StringBuilder();
int endIndex = Math.Min(byteArray.Length-1, index + count -1);
for(int i = index ; i <= endIndex ; i++)
{
stringBuilder.Append(System.Convert.ToChar(byteArray[i]));
}
return stringBuilder.ToString();
}
#endregion
#region 바이트 카운트 구하기 - GetByteCount(characterArray, characterArrayIndex, characterArrayCount)
/// <summary>
/// 바이트 카운트 구하기
/// </summary>
/// <param name="characterArray">문자 배열</param>
/// <param name="characterArrayIndex">문자 배열 인덱스</param>
/// <param name="characterArrayCount">문자 배열 카운트</param>
/// <returns>바이트 카운트</returns>
public override int GetByteCount(char[] characterArray, int characterArrayIndex, int characterArrayCount)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
#region 바이트 배열 구하기 - GetBytes(characterArray, characterArrayIndex, characterArrayCount, byteArray, byteArrayIndex)
/// <summary>
/// 바이트 배열 구하기
/// </summary>
/// <param name="characterArray">문자 배열</param>
/// <param name="characterArrayIndex">문자 배열 인덱스</param>
/// <param name="characterArrayCount">문자 배열 카운트</param>
/// <param name="byteArray">바이트 배열</param>
/// <param name="byteArrayIndex">바이트 배열 인덱스</param>
/// <returns>바이트 배열 카운트</returns>
public override int GetBytes(char[] characterArray, int characterArrayIndex, int characterArrayCount, byte[] byteArray, int byteArrayIndex)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
#region 최대 바이트 카운트 구하기 - GetMaxByteCount(characterCount)
/// <summary>
/// 최대 바이트 카운트 구하기
/// </summary>
/// <param name="characterCount">문자 카운트</param>
/// <returns>최대 바이트 카운트</returns>
public override int GetMaxByteCount(int characterCount)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
#region 문자 카운트 구하기 - GetCharCount(byteArray, byteArrayIndex, byteArrayCount)
/// <summary>
/// 문자 카운트 구하기
/// </summary>
/// <param name="byteArray">바이트 배열</param>
/// <param name="byteArrayIndex">바이트 배열 인덱스</param>
/// <param name="byteArrayCount">바이트 배열 카운트</param>
/// <returns>문자 카운트</returns>
public override int GetCharCount(byte[] byteArray, int byteArrayIndex, int byteArrayCount)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
#region 문자 배열 구하기 - GetChars(byteArray, byteArrayIndex, byteArrayCount, characterArray, characterArrayIndex)
/// <summary>
/// 문자 배열 구하기
/// </summary>
/// <param name="byteArray">바이트 배열</param>
/// <param name="byteArrayIndex">바이트 배열 인덱스</param>
/// <param name="byteArrayCount">바이트 배열 카운트</param>
/// <param name="characterArray">문자 배열</param>
/// <param name="characterArrayIndex">문자 배열 인덱스</param>
/// <returns>문자 배열 카운트</returns>
public override int GetChars(byte[] byteArray, int byteArrayIndex, int byteArrayCount, char[] characterArray, int characterArrayIndex)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
#region 최대 문자 카운트 구하기 - GetMaxCharCount(byteCount)
/// <summary>
/// 최대 문자 카운트 구하기
/// </summary>
/// <param name="byteCount">바이트 카운트</param>
/// <returns>최대 문자 카운트</returns>
public override int GetMaxCharCount(int byteCount)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
}
}
▶ ByteBuffer.cs
using System;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// 바이트 버퍼
/// </summary>
public class ByteBuffer
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region Field
/// <summary>
/// 카운트
/// </summary>
protected int count = 0;
/// <summary>
/// byte array
/// </summary>
protected byte[] bufferByteArray = new byte[16];
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 카운트 - Count
/// <summary>
/// 카운트
/// </summary>
public virtual int Count
{
get
{
return this.count;
}
}
#endregion
#region 인덱서 - this[index]
/// <summary>
/// 인덱서
/// </summary>
/// <param name="index">인덱스</param>
/// <returns>값</returns>
public byte this[int index]
{
get
{
if(index >= 0 && index < this.count)
{
return this.bufferByteArray[index];
}
else
{
throw new IndexOutOfRangeException("index");
}
}
set
{
if(index >= 0 && index < this.count)
{
this.bufferByteArray[index] = value;
}
else
{
throw new IndexOutOfRangeException("index");
}
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ByteBuffer()
/// <summary>
/// 생성자
/// </summary>
public ByteBuffer()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 추가하기 - Add(value)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="value">값</param>
public void Add(byte value)
{
FixBuffer(this.count + 1);
this.bufferByteArray[this.count] = value;
this.count ++;
}
#endregion
#region 추가하기 - Add(valueArray)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="valueArray">값 배열</param>
public void Add(byte[] valueArray)
{
if(valueArray != null)
{
Add(valueArray , 0 , valueArray.Length);
}
}
#endregion
#region 추가하기 - Add(valueArray , startIndex , length)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="valueArray">값 배열</param>
/// <param name="startIndex">시작 인덱스</param>
/// <param name="length">길이</param>
public void Add(byte[] valueArray , int startIndex , int length)
{
if(valueArray != null && startIndex >= 0 && (startIndex + length) <= valueArray.Length && length > 0)
{
FixBuffer(this.count + length);
Array.Copy(valueArray , startIndex , this.bufferByteArray , this.count , length);
this.count += length;
}
}
#endregion
#region 리셋하기 - Reset()
/// <summary>
/// 리셋하기
/// </summary>
public void Reset()
{
this.count = 0;
}
#endregion
#region 지우기 - Clear()
/// <summary>
/// 지우기
/// </summary>
public virtual void Clear()
{
this.bufferByteArray = new byte[16];
this.count = 0;
}
#endregion
#region 배열 구하기 - ToArray()
/// <summary>
/// 배열 구하기
/// </summary>
/// <returns>배열</returns>
public byte[] ToArray()
{
if(this.count > 0)
{
byte[] byteArray = new byte[this.count];
Array.Copy(this.bufferByteArray , 0 , byteArray , 0 , this.count);
return byteArray;
}
else
{
return null;
}
}
#endregion
#region 문자열 구하기 - GetString(encoding)
/// <summary>
/// 문자열 구하기
/// </summary>
/// <param name="encoding">인코딩</param>
/// <returns>문자열</returns>
public string GetString(Encoding encoding)
{
if(encoding == null)
{
throw new ArgumentNullException("encoding");
}
if(this.count > 0)
{
return encoding.GetString(this.bufferByteArray , 0 , this.count);
}
else
{
return String.Empty;
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 버퍼 수정하기 - FixBuffer(newSize)
/// <summary>
/// 버퍼 수정하기
/// </summary>
/// <param name="newSize">신규 크기</param>
protected void FixBuffer(int newSize)
{
if(newSize <= this.bufferByteArray.Length)
{
return;
}
if(newSize < (int)(this.bufferByteArray.Length * 1.5))
{
newSize = (int)(this.bufferByteArray.Length * 1.5);
}
byte[] byteArray = new byte[newSize];
Buffer.BlockCopy(this.bufferByteArray , 0 , byteArray , 0 , this.bufferByteArray.Length);
this.bufferByteArray = byteArray;
}
#endregion
}
}
▶ HeaderFooterStyle.cs
namespace TestLibrary
{
/// <summary>
/// 머리글/바닥글 스타일
/// </summary>
public enum HeaderFooterStyle
{
/// <summary>
/// 모든 페이지
/// </summary>
ALL_PAGES,
/// <summary>
/// 왼쪽 페이지
/// </summary>
LEFT_PAGES,
/// <summary>
/// 오른쪽 페이지
/// </summary>
RIGHT_PAGES,
/// <summary>
/// 첫번째 페이지
/// </summary>
FIRST_PAGE
}
}
▶ LevelNumberType.cs
namespace TestLibrary
{
/// <summary>
/// 레벨 번호 타입
/// </summary>
public enum LevelNumberType
{
/// <summary>
/// None
/// </summary>
NONE = -10,
/// <summary>
/// Arabic (1, 2, 3)
/// </summary>
ARABIC = 0,
/// <summary>
/// Uppercase Roman numeral (I, II, III)
/// </summary>
UPPERCASE_ROMAN_NUMERAL = 1,
/// <summary>
/// Lowercase Roman numeral (i, ii, iii)
/// </summary>
LOWERCASE_ROMAN_NUMERAL = 2,
/// <summary>
/// Uppercase letter (A, B, C)
/// </summary>
UPPERCASE_LETTER = 3,
/// <summary>
/// Lowercase letter (a, b, c)
/// </summary>
LOWERCASE_LETTER = 4,
/// <summary>
/// Ordinal number (1st, 2nd, 3rd)
/// </summary>
ORDINAL_NUMBER = 5,
/// <summary>
/// Cardinal text number (One, Two Three)
/// </summary>
CARDINAL_TEXT_NUMBER = 6,
/// <summary>
/// Ordinal text number (First, Second, Third)
/// </summary>
ORDINAL_TEXT_NUMBER = 7,
/// <summary>
/// Kanji numbering without the digit character (*dbnum1)
/// </summary>
KANJI_NUMBERING_WITHOUT_THE_DIGIT_CHARACTER = 10,
/// <summary>
/// Kanji numbering with the digit character (*dbnum2)
/// </summary>
KANJI_NUMBERING_WITH_THE_DIGIT_CHARACTER = 11,
/// <summary>
/// 46 phonetic katakana characters in "aiueo" order (*aiueo)
/// </summary>
_46_PHONETIC_KATAKANA_CHARACTERS_IN_AIUEO_ORDER = 12,
/// <summary>
/// 46 phonetic katakana characters in "iroha" order (*iroha)
/// </summary>
_46_PHONETIC_KATAKANA_CHARACTERS_IN_IROHA_ORDER = 13,
/// <summary>
/// Double byte character
/// </summary>
DOUBLE_BYTE_CHARACTER = 14,
/// <summary>
/// Single_byte character
/// </summary>
SINGLE_BYTE_CHARACTER = 15,
/// <summary>
/// Kanji numbering 3 (*dbnum3)
/// </summary>
KANJI_NUMBERING_3 = 16,
/// <summary>
/// Kanji numbering 4 (*dbnum4)
/// </summary>
KANJI_NUMBERING_4 = 17,
/// <summary>
/// Circle numbering (*circlenum)
/// </summary>
CIRCLE_NUMBERING = 18,
/// <summary>
/// Double_byte Arabic numbering
/// </summary>
DOUBLE_BYTE_ARABIC_NUMBERING = 19,
/// <summary>
/// 46 phonetic double_byte katakana characters (*aiueo*dbchar)
/// </summary>
_46_PHONETIC_DOUBLE_BYTE_KATAKANA_CHARACTERS_AIUEO_DBCHAR = 20,
/// <summary>
/// 46 phonetic double_byte katakana characters (*iroha*dbchar)
/// </summary>
_46_PHONETIC_DOUBLE_BYTE_KATAKANA_CHARACTERS_IROHA_DBCHAR = 21,
/// <summary>
/// Arabic with leading zero (01, 02, 03, ..., 10, 11)
/// </summary>
ARABIC_WITH_LEADING_ZERO = 22,
/// <summary>
/// Bullet (no number at all)
/// </summary>
BULLET = 23,
/// <summary>
/// Korean numbering 2 (*ganada)
/// </summary>
KOREAN_NUMBERING_2 = 24,
/// <summary>
/// Korean numbering 1 (*chosung)
/// </summary>
KOREAN_NUMBERING_1 = 25,
/// <summary>
/// Chinese numbering 1 (*gb1)
/// </summary>
CHINESE_NUMBERING_1 = 26,
/// <summary>
/// Chinese numbering 2 (*gb2)
/// </summary>
CHINESE_NUMBERING_2 = 27,
/// <summary>
/// Chinese numbering 3 (*gb3)
/// </summary>
CHINESE_NUMBERING_3 = 28,
/// <summary>
/// Chinese numbering 4 (*gb4)
/// </summary>
CHINESE_NUMBERING_4 = 29,
/// <summary>
/// Chinese Zodiac numbering 1 (* zodiac1)
/// </summary>
CHINESE_ZODIAC_NUMBERING_1 = 30,
/// <summary>
/// Chinese Zodiac numbering 2 (* zodiac2)
/// </summary>
CHINESE_ZODIAC_NUMBERING_2 = 31,
/// <summary>
/// Chinese Zodiac numbering 3 (* zodiac3)
/// </summary>
CHINESE_ZODIAC_NUMBERING_3 = 32,
/// <summary>
/// Taiwanese double_byte numbering 1
/// </summary>
TAIWANESE_DOUBLE_BYTE_NUMBERING_1 = 33,
/// <summary>
/// Taiwanese double_byte numbering 2
/// </summary>
TAIWANESE_DOUBLE_BYTE_NUMBERING_2 = 34,
/// <summary>
/// Taiwanese double_byte numbering 3
/// </summary>
TAIWANESE_DOUBLE_BYTE_NUMBERING_3 = 35,
/// <summary>
/// Taiwanese double_byte numbering 4
/// </summary>
TAIWANESE_DOUBLE_BYTE_NUMBERING_4 = 36,
/// <summary>
/// Chinese double_byte numbering 1
/// </summary>
CHINESE_DOUBLE_BYTE_NUMBERING_1 = 37,
/// <summary>
/// Chinese double_byte numbering 2
/// </summary>
CHINESE_DOUBLE_BYTE_NUMBERING_2 = 38,
/// <summary>
/// Chinese double_byte numbering 3
/// </summary>
CHINESE_DOUBLE_BYTE_NUMBERING_3 = 39,
/// <summary>
/// Chinese double_byte numbering 4
/// </summary>
CHINESE_DOUBLE_BYTE_NUMBERING_4 = 40,
/// <summary>
/// Korean double_byte numbering 1
/// </summary>
KOREAN_DOUBLE_BYTE_NUMBERING_1 = 41,
/// <summary>
/// Korean double_byte numbering 2
/// </summary>
KOREAN_DOUBLE_BYTE_NUMBERING_2 = 42,
/// <summary>
/// Korean double_byte numbering 3
/// </summary>
KOREAN_DOUBLE_BYTE_NUMBERING_3 = 43,
/// <summary>
/// Korean double_byte numbering 4
/// </summary>
KOREAN_DOUBLE_BYTE_NUMBERING_4 = 44,
/// <summary>
/// Hebrew non standard decimal
/// </summary>
HEBREW_NON_STANDARD_DECIMAL = 45,
/// <summary>
/// Arabic Alif Ba Tah
/// </summary>
ARABIC_ALIF_BA_TAH = 46,
/// <summary>
/// Hebrew Biblical standard
/// </summary>
HEBREW_BIBLICAL_STANDARD = 47,
/// <summary>
/// Arabic Abjad style
/// </summary>
ARABIC_ABJAD_STYLE = 48,
/// <summary>
/// No number
/// </summary>
NO_NUMBER = 255
}
}
▶ ProgressEventArgs.cs
using System;
namespace TestLibrary
{
/// <summary>
/// 진행 이벤트 인자
/// </summary>
public class ProgressEventArgs : EventArgs
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 최대 값
/// </summary>
private int maximumValue = 0;
/// <summary>
/// 값
/// </summary>
private int value = 0;
/// <summary>
/// 메시지
/// </summary>
private string message = null;
/// <summary>
/// 취소 여부
/// </summary>
private bool cancel = false;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 최대 값 - MaximumValue
/// <summary>
/// 최대 값
/// </summary>
public int MaximumValue
{
get
{
return this.maximumValue;
}
}
#endregion
#region 값 - Value
/// <summary>
/// 값
/// </summary>
public int Value
{
get
{
return this.value;
}
}
#endregion
#region 메시지 - Message
/// <summary>
/// 메시지
/// </summary>
public string Message
{
get
{
return this.message;
}
}
#endregion
#region 취소 여부 - Cancel
/// <summary>
/// 취소 여부
/// </summary>
public bool Cancel
{
get
{
return this.cancel;
}
set
{
this.cancel = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ProgressEventArgs(maximumValue, value, message)
/// <summary>
/// 생성자
/// </summary>
/// <param name="maximumValue">최대 값</param>
/// <param name="value">값</param>
/// <param name="message">메시지</param>
public ProgressEventArgs(int maximumValue, int value, string message)
{
this.maximumValue = maximumValue;
this.value = value;
this.message = message;
}
#endregion
}
}
▶ ProgressEventHandler.cs
namespace TestLibrary
{
/// <summary>
/// 진행 이벤트 핸들러
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
public delegate void ProgressEventHandler(object sender, ProgressEventArgs e);
}
▶ RTFAttribute.cs
using System;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// RTF 특성
/// </summary>
[Serializable]
public class RTFAttribute
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 명칭
/// </summary>
private string name = null;
/// <summary>
/// 값
/// </summary>
private int value = int.MinValue;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 명칭 - Name
/// <summary>
/// 명칭
/// </summary>
[DefaultValue( null)]
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
#endregion
#region 값 - Value
/// <summary>
/// 값
/// </summary>
[DefaultValue(int.MinValue)]
public int Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFAttribute()
/// <summary>
/// 생성자
/// </summary>
public RTFAttribute()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"{this.name}={this.value}";
}
#endregion
}
}
▶ RTFAttributeList.cs
using System;
using System.Collections;
using System.Diagnostics;
namespace TestLibrary
{
/// <summary>
/// RTF 특성 리스트
/// </summary>
[Serializable]
[DebuggerTypeProxy(typeof(RTFInstanceDebugView))]
public class RTFAttributeList : CollectionBase
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱서 - this[name]
/// <summary>
/// 인덱서
/// </summary>
/// <param name="name">명칭</param>
/// <returns>값</returns>
public int this[string name]
{
get
{
foreach(RTFAttribute attribute in this)
{
if(attribute.Name == name)
{
return attribute.Value;
}
}
return int.MinValue;
}
set
{
foreach(RTFAttribute attribute in this)
{
if(attribute.Name == name)
{
attribute.Value = value;
return;
}
}
RTFAttribute newAttribute = new RTFAttribute();
newAttribute.Name = name;
newAttribute.Value = value;
List.Add(newAttribute);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFAttributeList()
/// <summary>
/// 생성자
/// </summary>
public RTFAttributeList()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 추가하기 - Add(item)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="item">항목</param>
/// <returns>인덱스</returns>
public int Add(RTFAttribute item)
{
return List.Add(item);
}
#endregion
#region 추가하기 - Add(name, value)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="name">명칭</param>
/// <param name="value">값</param>
/// <returns>인덱스</returns>
public int Add(string name, int value)
{
RTFAttribute attribute = new RTFAttribute();
attribute.Name = name;
attribute.Value = value;
return List.Add(attribute);
}
#endregion
#region 제거하기 - Remove(item)
/// <summary>
/// 제거하기
/// </summary>
/// <param name="item">항목</param>
public void Remove(RTFAttribute item)
{
List.Remove(item);
}
#endregion
#region 제거하기 - Remove(name)
/// <summary>
/// 제거하기
/// </summary>
/// <param name="name">명칭</param>
public void Remove(string name)
{
for(int i = this.Count - 1; i >= 0; i--)
{
RTFAttribute item = (RTFAttribute)this.List[i];
if(item.Name == name)
{
List.RemoveAt(i);
}
}
}
#endregion
#region 항목 구하기 - GetItem(index)
/// <summary>
/// 항목 구하기
/// </summary>
/// <param name="index">인덱스</param>
/// <returns>항목</returns>
public RTFAttribute GetItem(int index)
{
return (RTFAttribute)List[index];
}
#endregion
#region 포함 여부 구하기 - Contains(item)
/// <summary>
/// 포함 여부 구하기
/// </summary>
/// <param name="item">항목</param>
/// <returns>포함 여부</returns>
public bool Contains(RTFAttribute item)
{
return List.Contains(item);
}
#endregion
#region 포함 여부 구하기 - Contains(name)
/// <summary>
/// 포함 여부 구하기
/// </summary>
/// <param name="name">명칭</param>
/// <returns>포함 여부</returns>
public bool Contains(string name)
{
foreach(RTFAttribute attribute in this)
{
if(attribute.Name == name)
{
return true;
}
}
return false;
}
#endregion
#region 복제하기 - Clone()
/// <summary>
/// 복제하기
/// </summary>
/// <returns>복제 리스트</returns>
public RTFAttributeList Clone()
{
RTFAttributeList list = new RTFAttributeList();
foreach(RTFAttribute item in this)
{
RTFAttribute newItem = new RTFAttribute();
newItem.Name = item.Name;
newItem.Value = item.Value;
list.List.Add(newItem);
}
return list;
}
#endregion
}
}
▶ RTFBorderStyle.cs
using System.Drawing ;
using System.Drawing.Drawing2D;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// RTF 테두리 스타일
/// </summary>
public class RTFBorderStyle
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 왼쪽 여부
/// </summary>
private bool left = false;
/// <summary>
/// 위쪽 여부
/// </summary>
private bool top = false;
/// <summary>
/// 오른쪽 여부
/// </summary>
private bool right = false;
/// <summary>
/// 아래쪽 여부
/// </summary>
private bool bottom = false;
/// <summary>
/// 두께
/// </summary>
private bool thickness = false;
/// <summary>
/// 스타일
/// </summary>
private DashStyle style = DashStyle.Solid;
/// <summary>
/// 색상
/// </summary>
private Color color = Color.Black;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Publicㄴ
#region 왼쪽 여부 - Left
/// <summary>
/// 왼쪽 여부
/// </summary>
[DefaultValue(false)]
public bool Left
{
get
{
return this.left;
}
set
{
this.left = value;
}
}
#endregion
#region 위쪽 여부 - Top
/// <summary>
/// 위쪽
/// </summary>
[DefaultValue(false)]
public bool Top
{
get
{
return this.top;
}
set
{
this.top = value;
}
}
#endregion
#region 오른쪽 여부 - Right
/// <summary>
/// 오른쪽 여부
/// </summary>
[DefaultValue(false)]
public bool Right
{
get
{
return this.right;
}
set
{
this.right = value;
}
}
#endregion
#region 아래쪽 여부 - Bottom
/// <summary>
/// 아래쪽 여부
/// </summary>
[DefaultValue(false)]
public bool Bottom
{
get
{
return this.bottom;
}
set
{
this.bottom = value;
}
}
#endregion
#region 두께 - Thickness
/// <summary>
/// 두께
/// </summary>
[DefaultValue(false)]
public bool Thickness
{
get
{
return this.thickness;
}
set
{
this.thickness = value;
}
}
#endregion
#region 스타일 - Style
/// <summary>
/// 스타일
/// </summary>
[DefaultValue(DashStyle.Solid)]
public DashStyle Style
{
get
{
return this.style;
}
set
{
this.style = value;
}
}
#endregion
#region 색상 - Color
/// <summary>
/// 색상
/// </summary>
[DefaultValue(typeof(Color), "Black")]
public Color Color
{
get
{
return this.color;
}
set
{
this.color = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Publicㄴ
#region 복제하기 - Clone()
/// <summary>
/// 복제하기
/// </summary>
/// <returns>RTF 테두리 스타일</returns>
public RTFBorderStyle Clone()
{
RTFBorderStyle stryle = new RTFBorderStyle();
stryle.left = this.left;
stryle.top = this.top;
stryle.right = this.right;
stryle.bottom = this.bottom;
stryle.thickness = this.thickness;
stryle.style = this.style;
stryle.color = this.color;
return stryle;
}
#endregion
#region 값 동일 여부 구하기 - EqualsValue(style)
/// <summary>
/// 값 동일 여부 구하기
/// </summary>
/// <param name="style">스타일</param>
/// <returns>값 동일 여부</returns>
public bool EqualsValue(RTFBorderStyle style)
{
if(style == this)
{
return true;
}
if(style == null)
{
return false;
}
if
(
style.bottom != this.bottom ||
style.color != this.color ||
style.left != this.left ||
style.right != this.right ||
style.style != this.style ||
style.top != this.top ||
style.thickness != this.thickness
)
{
return false;
}
else
{
return true;
}
}
#endregion
}
}
▶ RTFColorTable.cs
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
namespace TestLibrary
{
/// <summary>
/// RTF 색상 테이블
/// </summary>
[DebuggerDisplay("Count={Count}")]
[DebuggerTypeProxy(typeof(RTFInstanceDebugView))]
public class RTFColorTable
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 색상 리스트
/// </summary>
private List<Color> list = new List<Color>();
/// <summary>
/// 추가시 값 존재 체크 여부
/// </summary>
private bool checkValueExistWhenAdd = true;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱서 - this[index]
/// <summary>
/// 인덱서
/// </summary>
public Color this[int index]
{
get
{
return this.list[index];
}
}
#endregion
#region 추가시 값 존재 체크 여부 - CheckValueExistWhenAdd
/// <summary>
/// 추가시 값 존재 체크 여부
/// </summary>
public bool CheckValueExistWhenAdd
{
get
{
return this.checkValueExistWhenAdd;
}
set
{
this.checkValueExistWhenAdd = value;
}
}
#endregion
#region 카운트 - Count
/// <summary>
/// 카운트
/// </summary>
public int Count
{
get
{
return this.list.Count;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFColorTable()
/// <summary>
/// 생성자
/// </summary>
public RTFColorTable()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 추가하기 - Add(color)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="color">색상</param>
public void Add(Color color)
{
if(color.IsEmpty)
{
return;
}
if(color.A == 0)
{
return;
}
if(color.A != 255)
{
color = Color.FromArgb(255, color);
}
if(this.checkValueExistWhenAdd)
{
if(GetIndex(color) < 0)
{
this.list.Add(color);
}
}
else
{
this.list.Add(color);
}
}
#endregion
#region 제거하기 - Remove(color)
/// <summary>
/// 제거하기
/// </summary>
/// <param name="color">색상</param>
public void Remove(Color color)
{
int index = GetIndex(color);
if(index >= 0)
{
this.list.RemoveAt(index);
}
}
#endregion
#region 색상 구하기 - GetColor(index, defaultColor)
/// <summary>
/// 색상 구하기
/// </summary>
/// <param name="index">인덱스</param>
/// <param name="defaultColor">디폴트 색상</param>
/// <returns>색상</returns>
public Color GetColor(int index, Color defaultColor)
{
index--;
if(index >= 0 && index < this.list.Count)
{
return this.list[index];
}
else
{
return defaultColor;
}
}
#endregion
#region 인덱스 구하기 - GetIndex(color)
/// <summary>
/// 인덱스 구하기
/// </summary>
/// <param name="color">색상</param>
/// <returns>인덱스</returns>
public int GetIndex(Color color)
{
if(color.A == 0)
{
return -1;
}
if(color.A != 255)
{
color = Color.FromArgb(255 , color);
}
for(int i = 0; i < this.list.Count; i++)
{
if(this.list[i].ToArgb() == color.ToArgb())
{
return i;
}
}
return -1;
}
#endregion
#region 쓰기 - Write(writer)
/// <summary>
/// 쓰기
/// </summary>
/// <param name="writer">RTF 라이터</param>
public void Write(RTFWriter writer)
{
writer.WriteStartGroup();
writer.WriteKeyword(RTFConstant.COLORTBL);
writer.WriteRaw(";");
for(int i = 0; i < this.list.Count; i ++)
{
Color color = this.list[i];
writer.WriteKeyword("red" + color.R);
writer.WriteKeyword("green" + color.G);
writer.WriteKeyword("blue" + color.B);
writer.WriteRaw(";");
}
writer.WriteEndGroup();
}
#endregion
#region 지우기 - Clear()
/// <summary>
/// 지우기
/// </summary>
public void Clear()
{
this.list.Clear();
}
#endregion
#region 복제하기 - Clone()
/// <summary>
/// 복제하기
/// </summary>
/// <returns>RTF 색상 테이블</returns>
public RTFColorTable Clone()
{
RTFColorTable table = new RTFColorTable();
for(int i = 0; i < this.list.Count; i++)
{
Color color = this.list[i];
table.list.Add(color);
}
return table;
}
#endregion
}
}
▶ RTFConstant.cs
namespace TestLibrary
{
/// <summary>
/// RTF 상수
/// </summary>
public sealed class RTFConstant
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// INSRSID
/// </summary>
public const string INSRSID = "insrsid";
/// <summary>
/// AF
/// </summary>
public const string AF = "af";
/// <summary>
/// RTF
/// </summary>
public const string RTF = "rtf";
/// <summary>
/// FONTTBL
/// </summary>
public const string FONTTBL = "fonttbl";
/// <summary>
/// DOCFMT
/// </summary>
public const string DOCFMT = "docfmt";
/// <summary>
/// INFO
/// </summary>
public const string INFO = "info";
/// <summary>
/// AUTHOR
/// </summary>
public const string AUTHOR = "author";
/// <summary>
/// CREATIM
/// </summary>
public const string CREATIM = "creatim";
/// <summary>
/// VERSION
/// </summary>
public const string VERSION = "version";
/// <summary>
/// COLORTBL
/// </summary>
public const string COLORTBL = "colortbl";
/// <summary>
/// B
/// </summary>
public const string B = "b";
/// <summary>
/// BLUE
/// </summary>
public const string BLUE = "blue";
/// <summary>
/// ANSI
/// </summary>
public const string ANSI = "ansi";
/// <summary>
/// ANSICPG
/// </summary>
public const string ANSICPG = "ansicpg";
/// <summary>
/// MAC
/// </summary>
public const string MAC = "mac";
/// <summary>
/// PC
/// </summary>
public const string PC = "pc";
/// <summary>
/// PCA
/// </summary>
public const string PCA = "pca";
/// <summary>
/// FNIL
/// </summary>
public const string FNIL = "fnil";
/// <summary>
/// FROMAN
/// </summary>
public const string FROMAN = "froman";
/// <summary>
/// FSWISS
/// </summary>
public const string FSWISS = "fswiss";
/// <summary>
/// FMODERN
/// </summary>
public const string FMODERN = "fmodern";
/// <summary>
/// FSCRIPT
/// </summary>
public const string FSCRIPT = "fscript";
/// <summary>
/// FDECOR
/// </summary>
public const string FDECOR = "fdecor";
/// <summary>
/// FTECH
/// </summary>
public const string FTECH = "ftech";
/// <summary>
/// FBIDI
/// </summary>
public const string FBIDI = "fbidi";
/// <summary>
/// FCHARSET
/// </summary>
public const string FCHARSET = "fcharset";
/// <summary>
/// GENERATOR
/// </summary>
public const string GENERATOR = "generator";
/// <summary>
/// XMLNS
/// </summary>
public const string XMLNS = "xmlns";
/// <summary>
/// HEADER
/// </summary>
public const string HEADER = "header";
/// <summary>
/// FOOTER
/// </summary>
public const string FOOTER = "footer";
/// <summary>
/// HEADERL
/// </summary>
public const string HEADERL = "headerl";
/// <summary>
/// HEADERR
/// </summary>
public const string HEADERR = "headerr";
/// <summary>
/// HEADERF
/// </summary>
public const string HEADERF = "headerf";
/// <summary>
/// FOOTERL
/// </summary>
public const string FOOTERL = "footerl";
/// <summary>
/// FOOTERR
/// </summary>
public const string FOOTERR = "footerr";
/// <summary>
/// FOOTERF
/// </summary>
public const string FOOTERF = "footerf";
/// <summary>
/// HEADERY
/// </summary>
public const string HEADERY = "headery";
/// <summary>
/// FOOTERY
/// </summary>
public const string FOOTERY = "footery";
/// <summary>
/// STYLESHEET
/// </summary>
public const string STYLESHEET = "stylesheet";
/// <summary>
/// FILETBL
/// </summary>
public const string FILETBL = "filetbl";
/// <summary>
/// LISTTABLE
/// </summary>
public const string LISTTABLE = "listtable";
/// <summary>
/// LISTOVERRIDE
/// </summary>
public const string LISTOVERRIDE = "listoverride";
/// <summary>
/// REVTBL
/// </summary>
public const string REVTBL = "revtbl";
/// <summary>
/// NONSHPPICT
/// </summary>
public const string NONSHPPICT = "nonshppict";
/// <summary>
/// PNTEXT
/// </summary>
public const string PNTEXT = "pntext";
/// <summary>
/// PNTXTB
/// </summary>
public const string PNTXTB = "pntxtb";
/// <summary>
/// PNTXTA
/// </summary>
public const string PNTXTA = "pntxta";
/// <summary>
/// PAPERW
/// </summary>
public const string PAPERW = "paperw";
/// <summary>
/// PAPERH
/// </summary>
public const string PAPERH = "paperh";
/// <summary>
/// MARGL
/// </summary>
public const string MARGL = "margl";
/// <summary>
/// MARGR
/// </summary>
public const string MARGR = "margr";
/// <summary>
/// MARGB
/// </summary>
public const string MARGB = "margb";
/// <summary>
/// MARGT
/// </summary>
public const string MARGT = "margt";
/// <summary>
/// LANDSCAPE
/// </summary>
public const string LANDSCAPE = "landscape";
/// <summary>
/// PARD
/// </summary>
public const string PARD = "pard";
/// <summary>
/// PAGE
/// </summary>
public const string PAGE = "page";
/// <summary>
/// PAGEBB
/// </summary>
public const string PAGEBB = "pagebb";
/// <summary>
/// PAR
/// </summary>
public const string PAR = "par";
/// <summary>
/// QL
/// </summary>
public const string QL = "ql";
/// <summary>
/// QC
/// </summary>
public const string QC = "qc";
/// <summary>
/// QR
/// </summary>
public const string QR = "qr";
/// <summary>
/// QJ
/// </summary>
public const string QJ = "qj";
/// <summary>
/// FI
/// </summary>
public const string FI = "fi";
/// <summary>
/// SL
/// </summary>
public const string SL = "sl";
/// <summary>
/// SLMULT
/// </summary>
public const string SLMULT = "slmult";
/// <summary>
/// SB
/// </summary>
public const string SB = "sb";
/// <summary>
/// SA
/// </summary>
public const string SA = "sa";
/// <summary>
/// PN
/// </summary>
public const string PN = "pn";
/// <summary>
/// PNLVLBODY
/// </summary>
public const string PNLVLBODY = "pnlvlbody";
/// <summary>
/// PNLVLBLT
/// </summary>
public const string PNLVLBLT = "pnlvlblt";
/// <summary>
/// LISTTEXT
/// </summary>
public const string LISTTEXT = "listtext";
/// <summary>
/// LS
/// </summary>
public const string LS = "ls";
/// <summary>
/// LI
/// </summary>
public const string LI = "li";
/// <summary>
/// LINE
/// </summary>
public const string LINE = "line";
/// <summary>
/// PLAIN
/// </summary>
public const string PLAIN = "plain";
/// <summary>
/// F
/// </summary>
public const string F = "f";
/// <summary>
/// FS
/// </summary>
public const string FS = "fs";
/// <summary>
/// CF
/// </summary>
public const string CF = "cf";
/// <summary>
/// CB
/// </summary>
public const string CB = "cb";
/// <summary>
/// CHCBPAT
/// </summary>
public const string CHCBPAT = "chcbpat";
/// <summary>
/// I
/// </summary>
public const string I = "i";
/// <summary>
/// U
/// </summary>
public const string U = "u";
/// <summary>
/// V
/// </summary>
public const string V = "v";
/// <summary>
/// HIGHLIGHT
/// </summary>
public const string HIGHLIGHT = "highlight";
/// <summary>
/// UL
/// </summary>
public const string UL = "ul";
/// <summary>
/// NOUL
/// </summary>
public const string NOUL = "ulnone";
/// <summary>
/// STRIKE
/// </summary>
public const string STRIKE = "strike";
/// <summary>
/// SUB
/// </summary>
public const string SUB = "sub";
/// <summary>
/// SUPER
/// </summary>
public const string SUPER = "super";
/// <summary>
/// NOSUPERSUB
/// </summary>
public const string NOSUPERSUB = "nosupersub";
/// <summary>
/// BKMKSTART
/// </summary>
public const string BKMKSTART = "bkmkstart";
/// <summary>
/// BKMKEND
/// </summary>
public const string BKMKEND = "bkmkend";
/// <summary>
/// FIELD
/// </summary>
public const string FIELD = "field";
/// <summary>
/// FLDDIRTY
/// </summary>
public const string FLDDIRTY = "flddirty";
/// <summary>
/// FLDEDIT
/// </summary>
public const string FLDEDIT = "fldedit";
/// <summary>
/// FLDLOCK
/// </summary>
public const string FLDLOCK = "fldlock";
/// <summary>
/// FLDPRIV
/// </summary>
public const string FLDPRIV = "fldpriv";
/// <summary>
/// FLDINST
/// </summary>
public const string FLDINST = "fldinst";
/// <summary>
/// FLDRSLT
/// </summary>
public const string FLDRSLT = "fldrslt";
/// <summary>
/// HYPERLINK
/// </summary>
public const string HYPERLINK = "HYPERLINK";
/// <summary>
/// BLIPUID
/// </summary>
public const string BLIPUID = "blipuid";
/// <summary>
/// EMFBLIP
/// </summary>
public const string EMFBLIP = "emfblip";
/// <summary>
/// PNGBLIP
/// </summary>
public const string PNGBLIP = "pngblip";
/// <summary>
/// JPEGBLIP
/// </summary>
public const string JPEGBLIP = "jpegblip";
/// <summary>
/// MACPICT
/// </summary>
public const string MACPICT = "macpict";
/// <summary>
/// PMMETAFILE
/// </summary>
public const string PMMETAFILE = "pmmetafile";
/// <summary>
/// WMETAFILE
/// </summary>
public const string WMETAFILE = "wmetafile";
/// <summary>
/// DIBITMAP
/// </summary>
public const string DIBITMAP = "dibitmap";
/// <summary>
/// WBITMAP
/// </summary>
public const string WBITMAP = "wbitmap";
/// <summary>
/// SHPPICT
/// </summary>
public const string SHPPICT = "shppict";
/// <summary>
/// PICT
/// </summary>
public const string PICT = "pict";
/// <summary>
/// PICSCALEX
/// </summary>
public const string PICSCALEX = "picscalex";
/// <summary>
/// PICSCALEY
/// </summary>
public const string PICSCALEY = "picscaley";
/// <summary>
/// PICWGOAL
/// </summary>
public const string PICWGOAL = "picwgoal";
/// <summary>
/// PICHGOAL
/// </summary>
public const string PICHGOAL = "pichgoal";
/// <summary>
/// INTBL
/// </summary>
public const string INTBL = "intbl";
/// <summary>
/// TROWD
/// </summary>
public const string TROWD = "trowd";
/// <summary>
/// ITAP
/// </summary>
public const string ITAP = "itap";
/// <summary>
/// NESTTABLEPROPS
/// </summary>
public const string NESTTABLEPROPS = "nesttableprops";
/// <summary>
/// NESTROW
/// </summary>
public const string NESTROW = "nestrow";
/// <summary>
/// ROW
/// </summary>
public const string ROW = "row";
/// <summary>
/// IROWBAND
/// </summary>
public const string IROWBAND = "irowband";
/// <summary>
/// TRAUTOFIT
/// </summary>
public const string TRAUTOFIT = "trautofit";
/// <summary>
/// TRKEEPFOLLOW
/// </summary>
public const string TRKEEPFOLLOW = "trkeepfollow";
/// <summary>
/// TRQC
/// </summary>
public const string TRQC = "trqc";
/// <summary>
/// TRQL
/// </summary>
public const string TRQL = "trql";
/// <summary>
/// TRQR
/// </summary>
public const string TRQR = "trqr";
/// <summary>
/// TRHDR
/// </summary>
public const string TRHDR = "trhdr";
/// <summary>
/// TRRH
/// </summary>
public const string TRRH = "trrh";
/// <summary>
/// TRKEEP
/// </summary>
public const string TRKEEP = "trkeep";
/// <summary>
/// TRLEFT
/// </summary>
public const string TRLEFT = "trleft";
/// <summary>
/// TRCBPAT
/// </summary>
public const string TRCBPAT = "trcbpat";
/// <summary>
/// TRCFPAT
/// </summary>
public const string TRCFPAT = "trcfpat";
/// <summary>
/// TRPAT
/// </summary>
public const string TRPAT = "trpat";
/// <summary>
/// TRSHDNG
/// </summary>
public const string TRSHDNG = "trshdng";
/// <summary>
/// TRWWIDTH
/// </summary>
public const string TRWWIDTH = "trwWidth";
/// <summary>
/// TRWWIDTHA
/// </summary>
public const string TRWWIDTHA = "trwWidthA";
/// <summary>
/// IROW
/// </summary>
public const string IROW = "irow";
/// <summary>
/// TRPADDB
/// </summary>
public const string TRPADDB = "trpaddb";
/// <summary>
/// TRPADDL
/// </summary>
public const string TRPADDL = "trpaddl";
/// <summary>
/// TRPADDR
/// </summary>
public const string TRPADDR = "trpaddr";
/// <summary>
/// TRPADDT
/// </summary>
public const string TRPADDT = "trpaddt";
/// <summary>
/// TRPADDFB
/// </summary>
public const string TRPADDFB = "trpaddfb";
/// <summary>
/// TRPADDFL
/// </summary>
public const string TRPADDFL = "trpaddfl";
/// <summary>
/// TRPADDFR
/// </summary>
public const string TRPADDFR = "trpaddfr";
/// <summary>
/// TRPADDFT
/// </summary>
public const string TRPADDFT = "trpaddft";
/// <summary>
/// CLVMGF
/// </summary>
public const string CLVMGF = "clvmgf";
/// <summary>
/// CLVMRG
/// </summary>
public const string CLVMRG = "clvmrg";
/// <summary>
/// CELLX
/// </summary>
public const string CELLX = "cellx";
/// <summary>
/// CLVERTALT
/// </summary>
public const string CLVERTALT = "clvertalt";
/// <summary>
/// CLVERTALC
/// </summary>
public const string CLVERTALC = "clvertalc";
/// <summary>
/// CLVERTALB
/// </summary>
public const string CLVERTALB = "clvertalb";
/// <summary>
/// CLNOWRAP
/// </summary>
public const string CLNOWRAP = "clNoWrap";
/// <summary>
/// CLCBPAT
/// </summary>
public const string CLCBPAT = "clcbpat";
/// <summary>
/// CLCFPAT
/// </summary>
public const string CLCFPAT = "clcfpat";
/// <summary>
/// CLPADL
/// </summary>
public const string CLPADL = "clpadl";
/// <summary>
/// CLPADT
/// </summary>
public const string CLPADT = "clpadt";
/// <summary>
/// CLPADR
/// </summary>
public const string CLPADR = "clpadr";
/// <summary>
/// CLPADB
/// </summary>
public const string CLPADB = "clpadb";
/// <summary>
/// CLBRDRL
/// </summary>
public const string CLBRDRL = "clbrdrl";
/// <summary>
/// CLBRDRT
/// </summary>
public const string CLBRDRT = "clbrdrt";
/// <summary>
/// CLBRDRR
/// </summary>
public const string CLBRDRR = "clbrdrr";
/// <summary>
/// CLBRDRB
/// </summary>
public const string CLBRDRB = "clbrdrb";
/// <summary>
/// CELL
/// </summary>
public const string CELL = "cell";
/// <summary>
/// NESTCELL
/// </summary>
public const string NESTCELL = "nestcell";
/// <summary>
/// LASTROW
/// </summary>
public const string LASTROW = "lastrow";
/// <summary>
/// BRDRT
/// </summary>
public const string BRDRT = "brdrt";
/// <summary>
/// BRDRB
/// </summary>
public const string BRDRB = "brdrb";
/// <summary>
/// BRDRL
/// </summary>
public const string BRDRL = "brdrl";
/// <summary>
/// BRDRR
/// </summary>
public const string BRDRR = "brdrr";
/// <summary>
/// BRDRW
/// </summary>
public const string BRDRW = "brdrw";
/// <summary>
/// BRDRCF
/// </summary>
public const string BRDRCF = "brdrcf";
/// <summary>
/// BRDRS
/// </summary>
public const string BRDRS = "brdrs";
/// <summary>
/// BRDRTH
/// </summary>
public const string BRDRTH = "brdrth";
/// <summary>
/// BRDRDOT
/// </summary>
public const string BRDRDOT = "brdrdot";
/// <summary>
/// BRDRDASH
/// </summary>
public const string BRDRDASH = "brdrdash";
/// <summary>
/// BRDRDASHSM
/// </summary>
public const string BRDRDASHSM = "brdrdashsm";
/// <summary>
/// BRDRDASHD
/// </summary>
public const string BRDRDASHD = "brdrdashd";
/// <summary>
/// BRDRDASHDD
/// </summary>
public const string BRDRDASHDD = "brdrdashdd";
/// <summary>
/// CHBRDR
/// </summary>
public const string CHBRDR = "chbrdr";
/// <summary>
/// BRDRNIL
/// </summary>
public const string BRDRNIL = "brdrnil";
/// <summary>
/// BRDRTBL
/// </summary>
public const string BRDRTBL = "brdrtbl";
/// <summary>
/// BRDRNONE
/// </summary>
public const string BRDRNONE = "brdrnone";
/// <summary>
/// BRSP
/// </summary>
public const string BRSP = "brsp";
/// <summary>
/// NONESTTABLES
/// </summary>
public const string NONESTTABLES = "nonesttables";
/// <summary>
/// OBJECT
/// </summary>
public const string OBJECT = "object";
/// <summary>
/// OBJEMB
/// </summary>
public const string OBJEMB = "objemb";
/// <summary>
/// OBJLINK
/// </summary>
public const string OBJLINK = "objlink";
/// <summary>
/// OBJAUTLINK
/// </summary>
public const string OBJAUTLINK = "objautlink";
/// <summary>
/// OBJSUB
/// </summary>
public const string OBJSUB = "objsub";
/// <summary>
/// OBJPUB
/// </summary>
public const string OBJPUB = "objpub";
/// <summary>
/// OBJICEMB
/// </summary>
public const string OBJICEMB = "objicemb";
/// <summary>
/// OBJHTML
/// </summary>
public const string OBJHTML = "objhtml";
/// <summary>
/// OBJOCX
/// </summary>
public const string OBJOCX = "objocx";
/// <summary>
/// OBJCLASS
/// </summary>
public const string OBJCLASS = "objclass";
/// <summary>
/// OBJNAME
/// </summary>
public const string OBJNAME = "objname";
/// <summary>
/// OBJTIME
/// </summary>
public const string OBJTIME = "objtime";
/// <summary>
/// OBJH
/// </summary>
public const string OBJH = "objh";
/// <summary>
/// OBJW
/// </summary>
public const string OBJW = "objw";
/// <summary>
/// OBJSETSIZE
/// </summary>
public const string OBJSETSIZE = "objsetsize";
/// <summary>
/// OBJDATA
/// </summary>
public const string OBJDATA = "objdata";
/// <summary>
/// OBJALIAS
/// </summary>
public const string OBJALIAS = "objalias";
/// <summary>
/// OBJSECT
/// </summary>
public const string OBJSECT = "objsect";
/// <summary>
/// OBJSCALEX
/// </summary>
public const string OBJSCALEX = "objscalex";
/// <summary>
/// OBJSCALEY
/// </summary>
public const string OBJSCALEY = "objscaley";
/// <summary>
/// RESULT
/// </summary>
public const string RESULT = "result";
/// <summary>
/// SHP
/// </summary>
public const string SHP = "shp";
/// <summary>
/// SHPLEFT
/// </summary>
public const string SHPLEFT = "shpleft";
/// <summary>
/// SHPTOP
/// </summary>
public const string SHPTOP = "shptop";
/// <summary>
/// SHPBOTTOM
/// </summary>
public const string SHPBOTTOM = "shpbottom";
/// <summary>
/// SHPRIGHT
/// </summary>
public const string SHPRIGHT = "shpright";
/// <summary>
/// SHPLID
/// </summary>
public const string SHPLID = "shplid";
/// <summary>
/// SHPZ
/// </summary>
public const string SHPZ = "shpz";
/// <summary>
/// SHPTXT
/// </summary>
public const string SHPTXT = "shptxt";
/// <summary>
/// SHPGRP
/// </summary>
public const string SHPGRP = "shpgrp";
/// <summary>
/// BACKGROUND
/// </summary>
public const string BACKGROUND = "background";
/// <summary>
/// SHPRSLT
/// </summary>
public const string SHPRSLT = "shprslt";
/// <summary>
/// SHPINST
/// </summary>
public const string SHPINST = "shpinst";
/// <summary>
/// SP
/// </summary>
public const string SP = "sp";
/// <summary>
/// SN
/// </summary>
public const string SN = "sn";
/// <summary>
/// SV
/// </summary>
public const string SV = "sv";
/// <summary>
/// XMLOPEN
/// </summary>
public const string XMLOPEN = "xmlopen";
/// <summary>
/// FCHARS
/// </summary>
public const string FCHARS = "fchars";
/// <summary>
/// LCHARS
/// </summary>
public const string LCHARS = "lchars";
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 생성자 - RTFConstant()
/// <summary>
/// 생성자
/// </summary>
private RTFConstant()
{
}
#endregion
}
}
▶ RTFDocumentFormatInfo.cs
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace TestLibrary
{
/// <summary>
/// RTF 문서 포맷 정보
/// </summary>
[Serializable]
public class RTFDocumentFormatInfo
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 네이티브 레벨
/// </summary>
/// <remarks>
/// 기본 RTF 문서의 중첩 레벨
/// </remarks>
public int NativeLevel = 0;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region Field
/// <summary>
/// 텍스트 읽기 여부
/// </summary>
internal bool ReadText = true;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 부모 RTF 문서 포맷 정보
/// </summary>
private RTFDocumentFormatInfo parent = null;
/// <summary>
/// 페이지 브레이크 여부
/// </summary>
private bool pageBreak = false;
/// <summary>
/// 왼쪽 테두리 여부
/// </summary>
private bool leftBorder = false;
/// <summary>
/// 위쪽 테두리 여부
/// </summary>
private bool topBorder = false;
/// <summary>
/// 오른쪽 테두리
/// </summary>
private bool rightBorder = false;
/// <summary>
/// 아래쪽 테두리
/// </summary>
private bool bottomBorder = false;
/// <summary>
/// 테두리 두께 여부
/// </summary>
private bool borderThickness = false;
/// <summary>
/// 테두리 너비
/// </summary>
private int borderWidth = 0;
/// <summary>
/// 테두리 간격
/// </summary>
private int borderSpacing = 0;
/// <summary>
/// 테두리 색상
/// </summary>
private Color borderColor = Color.Black;
/// <summary>
/// 테두리 스타일
/// </summary>
private DashStyle borderStyle = DashStyle.Solid;
/// <summary>
/// 멀티 라인 여부
/// </summary>
private bool multiLine = false;
/// <summary>
/// 멀티 라인 간격 여부
/// </summary>
private bool multiLineSpacing = false;
/// <summary>
/// 라인 간격
/// </summary>
private int lineSpacing = 0;
/// <summary>
/// 문단 전 간격
/// </summary>
private int spacingBeforeParagraph = 0;
/// <summary>
/// 문단 후 간격
/// </summary>
private int spacingAfterParagraph = 0;
/// <summary>
/// 문단 첫번째 라인 들여쓰기
/// </summary>
private int paragraphFirstLineIndent = 0;
/// <summary>
/// 표준 탭 너비
/// </summary>
private int standardTabWidth = 100;
/// <summary>
/// 왼쪽 들여쓰기
/// </summary>
private int leftIndent = 0;
/// <summary>
/// 텍스트 정렬
/// </summary>
private RTFTextAlignment textAlignment = RTFTextAlignment.LEFT;
/// <summary>
/// 문자 간격
/// </summary>
private int characterSpacing = 0;
/// <summary>
/// 폰트명
/// </summary>
private string fontName = Control.DefaultFont.Name;
/// <summary>
/// 폰트 크기
/// </summary>
private float fontSize = 12f;
/// <summary>
/// 볼드체 여부
/// </summary>
private bool bold = false;
/// <summary>
/// 이탤릭체 여부
/// </summary>
private bool italic = false;
/// <summary>
/// 밑줄 여부
/// </summary>
private bool underline = false;
/// <summary>
/// 스트라이크 아웃 여부
/// </summary>
private bool strikeout = false;
/// <summary>
/// 숨김 여부
/// </summary>
private bool hidden = false;
/// <summary>
/// 텍스트 색상
/// </summary>
private Color textColor = Color.Black;
/// <summary>
/// 배경 색상
/// </summary>
private Color backgroundColor = Color.Empty;
/// <summary>
/// 링크
/// </summary>
private string link = null;
/// <summary>
/// 위 첨자 여부
/// </summary>
private bool superscript = false;
/// <summary>
/// 아래 첨자 여부
/// </summary>
private bool subscript = false;
/// <summary>
/// 목록 ID
/// </summary>
private int listID = -1;
/// <summary>
/// 노 랩 여부
/// </summary>
private bool noWrap = true;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 부모 RTF 문서 포맷 정보 - Parent
/// <summary>
/// 부모 RTF 문서 포맷 정보
/// </summary>
[Browsable(false)]
public RTFDocumentFormatInfo Parent
{
get
{
return this.parent;
}
}
#endregion
#region 페이지 브레이크 여부 - PageBreak
/// <summary>
/// 페이지 브레이크 여부
/// </summary>
[DefaultValue(false)]
public bool PageBreak
{
get
{
return this.pageBreak;
}
set
{
this.pageBreak = value;
}
}
#endregion
#region 왼쪽 테두리 여부 - LeftBorder
/// <summary>
/// 왼쪽 테두리 여부
/// </summary>
[DefaultValue(false)]
public bool LeftBorder
{
get
{
return this.leftBorder;
}
set
{
this.leftBorder = value;
}
}
#endregion
#region 위쪽 테두리 여부 - TopBorder
/// <summary>
/// 위쪽 테두리 여부
/// </summary>
[DefaultValue(false)]
public bool TopBorder
{
get
{
return this.topBorder;
}
set
{
this.topBorder = value;
}
}
#endregion
#region 오른쪽 테두리 - RightBorder
/// <summary>
/// 오른쪽 테두리
/// </summary>
[DefaultValue(false)]
public bool RightBorder
{
get
{
return this.rightBorder;
}
set
{
this.rightBorder = value;
}
}
#endregion
#region 아래쪽 테두리 - BottomBorder
/// <summary>
/// 아래쪽 테두리
/// </summary>
[DefaultValue(false)]
public bool BottomBorder
{
get
{
return this.bottomBorder;
}
set
{
this.bottomBorder = value;
}
}
#endregion
#region 테두리 두께 여부 - BorderThickness
/// <summary>
/// 테두리 두께 여부
/// </summary>
[DefaultValue(false)]
public bool BorderThickness
{
get
{
return this.borderThickness;
}
set
{
this.borderThickness = value;
}
}
#endregion
#region 테두리 너비 - BorderWidth
/// <summary>
/// 테두리 너비
/// </summary>
[DefaultValue(0)]
public int BorderWidth
{
get
{
return this.borderWidth;
}
set
{
this.borderWidth = value;
}
}
#endregion
#region 테두리 간격 - BorderSpacing
/// <summary>
/// 테두리 간격
/// </summary>
[DefaultValue(0)]
public int BorderSpacing
{
get
{
return this.borderSpacing;
}
set
{
this.borderSpacing = value;
}
}
#endregion
#region 테두리 색상 - BorderColor
/// <summary>
/// 테두리 색상
/// </summary>
[DefaultValue(typeof(Color), "Black")]
public Color BorderColor
{
get
{
return this.borderColor;
}
set
{
this.borderColor = value;
}
}
#endregion
#region 테두리 스타일 - BorderStyle
/// <summary>
/// 테두리 스타일
/// </summary>
[DefaultValue(DashStyle.Solid)]
public DashStyle BorderStyle
{
get
{
return this.borderStyle;
}
set
{
this.borderStyle = value;
}
}
#endregion
#region 멀티 라인 여부 - MultiLine
/// <summary>
/// 멀티 라인 여부
/// </summary>
[DefaultValue(false)]
public bool MultiLine
{
get
{
return this.multiLine;
}
set
{
this.multiLine = value;
}
}
#endregion
#region 멀티 라인 간격 여부 - MultiLineSpacing
/// <summary>
/// 멀티 라인 간격 여부
/// </summary>
[DefaultValue(false)]
public bool MultiLineSpacing
{
get
{
return this.multiLineSpacing;
}
set
{
this.multiLineSpacing = value;
}
}
#endregion
#region 라인 간격 - LineSpacing
/// <summary>
/// 라인 간격
/// </summary>
[DefaultValue(0)]
public int LineSpacing
{
get
{
return this.lineSpacing;
}
set
{
this.lineSpacing = value;
}
}
#endregion
#region 문단 전 간격 - SpacingBeforeParagraph
/// <summary>
/// 문단 전 간격
/// </summary>
[DefaultValue(0)]
public int SpacingBeforeParagraph
{
get
{
return this.spacingBeforeParagraph;
}
set
{
this.spacingBeforeParagraph = value;
}
}
#endregion
#region 문단 후 간격 - SpacingAfterParagraph
/// <summary>
/// 문단 후 간격
/// </summary>
[DefaultValue(0)]
public int SpacingAfterParagraph
{
get
{
return this.spacingAfterParagraph;
}
set
{
this.spacingAfterParagraph = value;
}
}
#endregion
#region 문단 첫번째 라인 들여쓰기 - ParagraphFirstLineIndent
/// <summary>
/// 문단 첫번째 라인 들여쓰기
/// </summary>
[DefaultValue(0)]
public int ParagraphFirstLineIndent
{
get
{
return this.paragraphFirstLineIndent;
}
set
{
this.paragraphFirstLineIndent = value;
}
}
#endregion
#region 표준 탭 너비 - StandTabWidth
/// <summary>
/// 표준 탭 너비
/// </summary>
[DefaultValue(100)]
public int StandTabWidth
{
get
{
return this.standardTabWidth;
}
set
{
this.standardTabWidth = value;
}
}
#endregion
#region 왼쪽 들여쓰기 - LeftIndent
/// <summary>
/// 왼쪽 들여쓰기
/// </summary>
[DefaultValue(0)]
public int LeftIndent
{
get
{
return this.leftIndent;
}
set
{
this.leftIndent = value;
}
}
#endregion
#region 텍스트 정렬 - TextAlignment
/// <summary>
/// 텍스트 정렬
/// </summary>
[DefaultValue(RTFTextAlignment.LEFT)]
public RTFTextAlignment TextAlignment
{
get
{
return this.textAlignment;
}
set
{
this.textAlignment = value;
}
}
#endregion
#region 문자 간격 - CharacterSpacing
/// <summary>
/// 문자 간격
/// </summary>
[DefaultValue(0)]
public int CharacterSpacing
{
get
{
return this.characterSpacing;
}
set
{
this.characterSpacing = value;
}
}
#endregion
#region 폰트 - Font
/// <summary>
/// 폰트
/// </summary>
[Browsable(false)]
public Font Font
{
set
{
if(value != null)
{
FontName = value.Name;
FontSize = value.Size;
Bold = value.Bold;
Italic = value.Italic;
Underline = value.Underline;
Strikeout = value.Strikeout;
}
}
}
#endregion
#region 폰트명 - FontName
/// <summary>
/// 폰트명
/// </summary>
public string FontName
{
get
{
return this.fontName;
}
set
{
this.fontName = value;
}
}
#endregion
#region 폰트 크기 - FontSize
/// <summary>
/// 폰트 크기
/// </summary>
[DefaultValue(12f)]
public float FontSize
{
get
{
return this.fontSize;
}
set
{
this.fontSize = value;
}
}
#endregion
#region 볼드체 여부 - Bold
/// <summary>
/// 볼드체 여부
/// </summary>
[DefaultValue(false)]
public bool Bold
{
get
{
return this.bold;
}
set
{
this.bold = value;
}
}
#endregion
#region 이탤릭체 여부 - Italic
/// <summary>
/// 이탤릭체 여부
/// </summary>
[DefaultValue(false)]
public bool Italic
{
get
{
return this.italic;
}
set
{
this.italic = value;
}
}
#endregion
#region 밑줄 여부 - Underline
/// <summary>
/// 밑줄 여부
/// </summary>
[DefaultValue(false)]
public bool Underline
{
get
{
return this.underline;
}
set
{
this.underline = value;
}
}
#endregion
#region 스트라이크 아웃 여부 - Strikeout
/// <summary>
/// 스트라이크 아웃 여부
/// </summary>
[DefaultValue(false)]
public bool Strikeout
{
get
{
return this.strikeout;
}
set
{
this.strikeout = value;
}
}
#endregion
#region 위 첨자 여부 - Superscript
/// <summary>
/// 위 첨자 여부
/// </summary>
[DefaultValue(false)]
public bool Superscript
{
get
{
return this.superscript;
}
set
{
this.superscript = value;
if(this.superscript)
{
this.subscript = false;
}
}
}
#endregion
#region 아래 첨자 여부 - Subscript
/// <summary>
/// 아래 첨자 여부
/// </summary>
[DefaultValue(false)]
public bool Subscript
{
get
{
return this.subscript;
}
set
{
this.subscript = value;
if(this.subscript)
{
this.superscript = false;
}
}
}
#endregion
#region 숨김 여부 - Hidden
/// <summary>
/// 숨김 여부
/// </summary>
[DefaultValue(false)]
public bool Hidden
{
get
{
return this.hidden;
}
set
{
this.hidden = value;
}
}
#endregion
#region 텍스트 색상 - TextColor
/// <summary>
/// 텍스트 색상
/// </summary>
[DefaultValue(typeof(Color), "Black")]
public Color TextColor
{
get
{
return this.textColor;
}
set
{
this.textColor = value;
}
}
#endregion
#region 배경 색상 - BackgroundColor
/// <summary>
/// 배경 색상
/// </summary>
[DefaultValue(typeof(Color), "Empty")]
public Color BackgroundColor
{
get
{
return this.backgroundColor;
}
set
{
this.backgroundColor = value;
}
}
#endregion
#region 링크 - Link
/// <summary>
/// 링크
/// </summary>
[DefaultValue(null)]
public string Link
{
get
{
return this.link;
}
set
{
this.link = value;
}
}
#endregion
#region 목록 ID - ListID
/// <summary>
/// 목록 ID
/// </summary>
public int ListID
{
get
{
return this.listID;
}
set
{
this.listID = value;
}
}
#endregion
#region 노 랩 여부 - NoWrap
/// <summary>
/// 노 랩 여부
/// </summary>
[DefaultValue(true)]
public bool NoWrap
{
get
{
return this.noWrap;
}
set
{
this.noWrap = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDocumentFormatInfo()
/// <summary>
/// 생성자
/// </summary>
public RTFDocumentFormatInfo()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 복제하기 - Clone()
/// <summary>
/// 복제하기
/// </summary>
/// <returns>RTF 문서 포맷 정보</returns>
public RTFDocumentFormatInfo Clone()
{
return (RTFDocumentFormatInfo)MemberwiseClone();
}
#endregion
#region 설정 동일 여부 구하기 - EqualsSettings(source)
/// <summary>
/// 설정 동일 여부 구하기
/// </summary>
/// <param name="source">소스 RTF 문서 포맷 정보</param>
/// <returns>설정 동일 여부</returns>
public bool EqualsSettings(RTFDocumentFormatInfo source)
{
if(source == this)
{
return true;
}
if(source == null)
{
return false;
}
if(TextAlignment != source.TextAlignment)
{
return false;
}
if(BackgroundColor != source.BackgroundColor)
{
return false;
}
if(Bold != source.Bold)
{
return false;
}
if(BorderColor != source.BorderColor)
{
return false;
}
if(LeftBorder != source.LeftBorder)
{
return false;
}
if(TopBorder != source.TopBorder)
{
return false;
}
if(RightBorder != source.RightBorder)
{
return false;
}
if(BottomBorder != source.BottomBorder)
{
return false;
}
if(BorderStyle != source.BorderStyle)
{
return false;
}
if(BorderThickness != source.BorderThickness)
{
return false;
}
if(BorderSpacing != source.BorderSpacing)
{
return false;
}
if(ListID != source.ListID)
{
return false;
}
if(FontName != source.FontName)
{
return false;
}
if(FontSize != source.FontSize)
{
return false;
}
if(Italic != source.Italic)
{
return false;
}
if(Hidden != source.Hidden)
{
return false;
}
if(LeftIndent != source.LeftIndent)
{
return false;
}
if(LineSpacing != source.LineSpacing)
{
return false;
}
if(Link != source.Link)
{
return false;
}
if(MultiLine != source.MultiLine)
{
return false;
}
if(NoWrap != source.NoWrap)
{
return false;
}
if(ParagraphFirstLineIndent != source.ParagraphFirstLineIndent)
{
return false;
}
if(CharacterSpacing != source.CharacterSpacing)
{
return false;
}
if(StandTabWidth != source.StandTabWidth)
{
return false;
}
if(Strikeout != source.Strikeout)
{
return false;
}
if(Subscript != source.Subscript)
{
return false;
}
if(Superscript != source.Superscript)
{
return false;
}
if(TextColor != source.TextColor)
{
return false;
}
if(Underline != source.Underline)
{
return false;
}
if(ReadText != source.ReadText)
{
return false;
}
return true;
}
#endregion
#region 정렬 설정하기 - SetAlignment(alignment)
/// <summary>
/// 정렬 설정하기
/// </summary>
/// <param name="alignment">정렬</param>
public void SetAlignment(StringAlignment alignment)
{
if(alignment == StringAlignment.Center)
{
this.TextAlignment = RTFTextAlignment.CENTER;
}
else if(alignment == StringAlignment.Far)
{
this.TextAlignment = RTFTextAlignment.RIGHT;
}
else
{
this.TextAlignment = RTFTextAlignment.LEFT;
}
}
#endregion
#region 리셋하기 - Reset()
/// <summary>
/// 리셋하기
/// </summary>
public void Reset()
{
ParagraphFirstLineIndent = 0;
LeftIndent = 0;
LeftIndent = 0;
CharacterSpacing = 0;
LineSpacing = 0;
MultiLineSpacing = false;
SpacingBeforeParagraph = 0;
SpacingAfterParagraph = 0;
TextAlignment = 0;
FontName = Control.DefaultFont.Name;
FontSize = 12;
Bold = false;
Italic = false;
Underline = false;
Strikeout = false;
TextColor = Color.Black;
BackgroundColor = Color.Empty;
Link = null;
Subscript = false;
Superscript = false;
ListID = -1;
MultiLine = true;
NoWrap = true;
LeftBorder = false;
TopBorder = false;
RightBorder = false;
BottomBorder = false;
BorderStyle = DashStyle.Solid;
BorderSpacing = 0;
BorderThickness = false;
BorderColor = Color.Black;
ReadText = true;
NativeLevel = 0;
Hidden = false;
}
#endregion
#region 문단 리셋하기 - ResetParagraph()
/// <summary>
/// 문단 리셋하기
/// </summary>
public void ResetParagraph()
{
ParagraphFirstLineIndent = 0;
TextAlignment = 0;
ListID = -1;
LeftIndent = 0;
LineSpacing = 0;
PageBreak = false;
LeftBorder = false;
TopBorder = false;
RightBorder = false;
BottomBorder = false;
BorderStyle = DashStyle.Solid;
BorderSpacing = 0;
BorderThickness = false;
BorderColor = Color.Black ;
MultiLineSpacing = false;
SpacingBeforeParagraph = 0;
SpacingAfterParagraph = 0;
}
#endregion
#region 텍스트 리셋하기 - ResetText()
/// <summary>
/// 텍스트 리셋하기
/// </summary>
public void ResetText()
{
FontName = Control.DefaultFont.Name;
FontSize = 12;
Bold = false;
Italic = false;
Underline = false;
Strikeout = false;
TextColor = Color.Black;
BackgroundColor = Color.Empty;
Subscript = false;
Superscript = false;
MultiLine = true;
Hidden = false;
LeftBorder = false;
TopBorder = false;
RightBorder = false;
BottomBorder = false;
BorderStyle = DashStyle.Solid;
BorderSpacing = 0;
BorderThickness = false;
BorderColor = Color.Black;
}
#endregion
}
}
▶ RTFDocumentInfo.cs
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
namespace TestLibrary
{
/// <summary>
/// RTF 문서 정보
/// </summary>
[Serializable]
[DebuggerTypeProxy(typeof(RTFInstanceDebugView))]
public class RTFDocumentInfo
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 딕셔너리
/// </summary>
private StringDictionary dictionary = new StringDictionary();
/// <summary>
/// 생성 시간
/// </summary>
private DateTime createTime = DateTime.Now;
/// <summary>
/// 수정 시간
/// </summary>
private DateTime updateTime = DateTime.Now;
/// <summary>
/// 인쇄 시간
/// </summary>
private DateTime printTime = DateTime.Now;
/// <summary>
/// 백업 시간
/// </summary>
private DateTime backupTime = DateTime.Now;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 제목 - Title
/// <summary>
/// 제목
/// </summary>
public string Title
{
get
{
return this.dictionary["title"];
}
set
{
this.dictionary["title"] = value;
}
}
#endregion
#region 주제 - Subject
/// <summary>
/// 주제
/// </summary>
public string Subject
{
get
{
return this.dictionary["subject"];
}
set
{
this.dictionary["subject"] = value;
}
}
#endregion
#region 저자 - Author
/// <summary>
/// 저자
/// </summary>
public string Author
{
get
{
return this.dictionary["author"];
}
set
{
this.dictionary["author"] = value;
}
}
#endregion
#region 관리자 - Manager
/// <summary>
/// 관리자
/// </summary>
public string Manager
{
get
{
return this.dictionary["manager"];
}
set
{
this.dictionary["manager"] = value;
}
}
#endregion
#region 회사 - Company
/// <summary>
/// 회사
/// </summary>
public string Company
{
get
{
return this.dictionary["company"];
}
set
{
this.dictionary["company"] = value;
}
}
#endregion
#region 연산자 - Operator
/// <summary>
/// 연산자
/// </summary>
public string Operator
{
get
{
return this.dictionary["operator"];
}
set
{
this.dictionary["operator"] = value;
}
}
#endregion
#region 카테고리 - Category
/// <summary>
/// 카테고리
/// </summary>
public string Category
{
get
{
return this.dictionary["category"];
}
set
{
this.dictionary["categroy"] = value;
}
}
#endregion
#region 키워드 - Keywords
/// <summary>
/// 키워드
/// </summary>
public string Keywords
{
get
{
return this.dictionary["keywords"];
}
set
{
this.dictionary["keywords"] = value;
}
}
#endregion
#region 주석 - Comment
/// <summary>
/// 주석
/// </summary>
public string Comment
{
get
{
return this.dictionary["comment"];
}
set
{
this.dictionary["comment"] = value;
}
}
#endregion
#region 문서 주석 - DocumentCommenct
/// <summary>
/// 문서 주석
/// </summary>
public string DocumentCommenct
{
get
{
return this.dictionary["doccomm"];
}
set
{
this.dictionary["doccomm"] = value;
}
}
#endregion
#region 기본 하이퍼링크 - BaseHyperlink
/// <summary>
/// 기본 하이퍼링크
/// </summary>
public string BaseHyperlink
{
get
{
return this.dictionary["hlinkbase"];
}
set
{
this.dictionary["hlinkbase"] = value;
}
}
#endregion
#region 전체 편집 분 카운트 - TotalEditMinuteCount
/// <summary>
/// 전체 편집 분 카운트
/// </summary>
public int TotalEditMinuteCount
{
get
{
if(this.dictionary.ContainsKey("edmins"))
{
string totalEditMinuteCountString = Convert.ToString(this.dictionary["edmins"]);
int result;
if(int.TryParse(totalEditMinuteCountString, out result))
{
return result;
}
}
return 0;
}
set
{
this.dictionary["edmins"] = value.ToString();
}
}
#endregion
#region 버전 - Version
/// <summary>
/// 버전
/// </summary>
public string Version
{
get
{
return this.dictionary["vern"];
}
set
{
this.dictionary["vern"] = value;
}
}
#endregion
#region 페이지 카운트 - PageCount
/// <summary>
/// 페이지 카운트
/// </summary>
public string PageCount
{
get
{
return this.dictionary["nofpages"];
}
set
{
this.dictionary["nofpages"] = value;
}
}
#endregion
#region 단어 카운트 - WordCount
/// <summary>
/// 단어 카운트
/// </summary>
public string WordCount
{
get
{
return this.dictionary["nofwords"];
}
set
{
this.dictionary["nofwords"] = value;
}
}
#endregion
#region 문자 카운트 (공백 문자열 포함) - CharacterCount
/// <summary>
/// 문자 카운트 (공백 문자열 포함)
/// </summary>
public string CharacterCount
{
get
{
return this.dictionary["nofchars"];
}
set
{
this.dictionary["nofchars"] = value;
}
}
#endregion
#region 문자 카운트 (공백 문자열 제외) - CharacterCountExcludingWhiteSpace
/// <summary>
/// 문자 카운트 (공백 문자열 제외)
/// </summary>
public string CharacterCountExcludingWhiteSpace
{
get
{
return this.dictionary["nofcharsws"];
}
set
{
this.dictionary["nofcharsws"] = value;
}
}
#endregion
#region ID - ID
/// <summary>
/// ID
/// </summary>
public string ID
{
get
{
return this.dictionary["id"];
}
set
{
this.dictionary["id"] = value;
}
}
#endregion
#region 생성 시간 - CreateTime
/// <summary>
/// 생성 시간
/// </summary>
public DateTime CreateTime
{
get
{
return this.createTime;
}
set
{
this.createTime = value;
}
}
#endregion
#region 수정 시간 - UpdateTime
/// <summary>
/// 수정 시간
/// </summary>
public DateTime UpdateTime
{
get
{
return this.updateTime;
}
set
{
this.updateTime = value;
}
}
#endregion
#region 인쇄 시간 - PrintTime
/// <summary>
/// 인쇄 시간
/// </summary>
public DateTime PrintTime
{
get
{
return this.printTime;
}
set
{
this.printTime = value;
}
}
#endregion
#region 백업 시간 - BackupTime
/// <summary>
/// 백업 시간
/// </summary>
public DateTime BackupTime
{
get
{
return this.backupTime;
}
set
{
this.backupTime = value;
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region 항목 배열 - ItemArray
/// <summary>
/// 항목 배열
/// </summary>
internal string[] ItemArray
{
get
{
List<string> list = new List<string>();
foreach(string key in this.dictionary.Keys)
{
list.Add(key + "=" + this.dictionary[key]);
}
list.Add("Creatim=" + CreateTime.ToString("yyyy-MM-dd HH:mm:ss"));
list.Add("Revtim=" + UpdateTime.ToString("yyyy-MM-dd HH:mm:ss"));
list.Add("Printim=" + PrintTime.ToString ("yyyy-MM-dd HH:mm:ss"));
list.Add("Buptim=" + BackupTime.ToString("yyyy-MM-dd HH:mm:ss"));
return list.ToArray();
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 정보 설정하기 - SetInfo(name , value)
/// <summary>
/// 정보 설정하기
/// </summary>
/// <param name="name">명칭</param>
/// <param name="value">값</param>
public void SetInfo(string name , string value)
{
this.dictionary[name] = value;
}
#endregion
#region 정보 구하기 - GetInfo(name)
/// <summary>
/// 정보 구하기
/// </summary>
/// <param name="name">명칭</param>
/// <returns>정보</returns>
public string GetInfo(string name)
{
return this.dictionary[name];
}
#endregion
#region 쓰기 - Write(writer)
/// <summary>
/// 쓰기
/// </summary>
/// <param name="writer">RTF 라이터</param>
public void Write(RTFWriter writer)
{
writer.WriteStartGroup();
writer.WriteKeyword("info");
foreach(string key in this.dictionary.Keys)
{
writer.WriteStartGroup();
if
( key == "edmins" ||
key == "vern" ||
key == "nofpages" ||
key == "nofwords" ||
key == "nofchars" ||
key == "nofcharsws" ||
key == "id"
)
{
writer.WriteKeyword(key + this.dictionary[key]);
}
else
{
writer.WriteKeyword(key);
writer.WriteText(this.dictionary[key]);
}
writer.WriteEndGroup();
}
writer.WriteStartGroup();
WriteTime(writer, "creatim", this.createTime);
WriteTime(writer, "revtim" , this.updateTime);
WriteTime(writer, "printim", this.printTime );
WriteTime(writer, "buptim" , this.backupTime);
writer.WriteEndGroup();
}
#endregion
#region 지우기 - Clear()
/// <summary>
/// 지우기
/// </summary>
public void Clear()
{
this.dictionary.Clear();
DateTime currentTime = DateTime.Now;
this.createTime = currentTime;
this.updateTime = currentTime;
this.printTime = currentTime;
this.backupTime = currentTime;
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 시간 쓰기 - WriteTime(writer, name, value)
/// <summary>
/// 시간 쓰기
/// </summary>
/// <param name="writer">RTF 라이터</param>
/// <param name="name">명칭</param>
/// <param name="value">값</param>
private void WriteTime(RTFWriter writer, string name, DateTime value)
{
writer.WriteStartGroup();
writer.WriteKeyword(name);
writer.WriteKeyword("yr" + value.Year );
writer.WriteKeyword("mo" + value.Month );
writer.WriteKeyword("dy" + value.Day );
writer.WriteKeyword("hr" + value.Hour );
writer.WriteKeyword("min" + value.Minute);
writer.WriteKeyword("sec" + value.Second);
writer.WriteEndGroup();
}
#endregion
}
}
▶ RTFDocumentWriter.cs
using System;
using System.Collections ;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace TestLibrary
{
/// <summary>
/// RTF 문서 라이터
/// </summary>
public class RTFDocumentWriter
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// RTF 라이터
/// </summary>
private RTFWriter writer = null;
/// <summary>
/// 문서 정보 해시 테이블
/// </summary>
private Hashtable documentInfoHashtable = new Hashtable();
/// <summary>
/// 폰트 테이블
/// </summary>
private RTFFontTable fontTable = new RTFFontTable();
/// <summary>
/// 리스트 테이블
/// </summary>
private RTFListTable listTable = new RTFListTable();
/// <summary>
/// 리스트 오버라이드 테이블
/// </summary>
private RTFListOverrideTable listOverrideTable = new RTFListOverrideTable();
/// <summary>
/// 색상 테이블
/// </summary>
private RTFColorTable colorTable = new RTFColorTable();
/// <summary>
/// 문서 정보 수집 여부
/// </summary>
private bool collectDocumentInfo = true;
/// <summary>
/// 디버그 모드
/// </summary>
private bool debugMode = true;
/// <summary>
/// 마지막 문단 정보
/// </summary>
private RTFDocumentFormatInfo lastParagraphInfo = null;
/// <summary>
/// 첫번째 문단 여부
/// </summary>
private bool firstParagraph = true;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region RTF 라이터 - Writer
/// <summary>
/// RTF 라이터
/// </summary>
public RTFWriter Writer
{
get
{
return this.writer;
}
set
{
this.writer = value;
}
}
#endregion
#region 문서 정보 해시 테이블 - DocumentInfoHashtable
/// <summary>
/// 문서 정보 해시 테이블
/// </summary>
public Hashtable DocumentInfoHashtable
{
get
{
return this.documentInfoHashtable;
}
}
#endregion
#region 폰트 테이블 - FontTable
/// <summary>
/// 폰트 테이블
/// </summary>
public RTFFontTable FontTable
{
get
{
return this.fontTable;
}
}
#endregion
#region 리스트 테이블 - ListTable
/// <summary>
/// 리스트 테이블
/// </summary>
public RTFListTable ListTable
{
get
{
return this.listTable;
}
set
{
this.listTable = value;
}
}
#endregion
#region 리스트 오버라이드 테이블 - ListOverrideTable
/// <summary>
/// 리스트 오버라이드 테이블
/// </summary>
public RTFListOverrideTable ListOverrideTable
{
get
{
return this.listOverrideTable;
}
set
{
this.listOverrideTable = value;
}
}
#endregion
#region 색상 테이블 - ColorTable
/// <summary>
/// 색상 테이블
/// </summary>
public RTFColorTable ColorTable
{
get
{
return this.colorTable;
}
}
#endregion
#region 문서 정보 수집 여부 - CollectDocumentInfo
/// <summary>
/// 문서 정보 수집 여부
/// </summary>
public bool CollectDocumentInfo
{
get
{
return this.collectDocumentInfo;
}
set
{
this.collectDocumentInfo = value;
}
}
#endregion
#region 그룹 레벨 - GroupLevel
/// <summary>
/// 그룹 레벨
/// </summary>
public int GroupLevel
{
get
{
return this.writer.GroupLevel;
}
}
#endregion
#region 디버그 모드 - DebugMode
/// <summary>
/// 디버그 모드
/// </summary>
public bool DebugMode
{
get
{
return this.debugMode;
}
set
{
this.debugMode = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDocumentWriter()
/// <summary>
/// 생성자
/// </summary>
public RTFDocumentWriter()
{
this.colorTable.CheckValueExistWhenAdd = true;
}
#endregion
#region 생성자 - RTFDocumentWriter(writer)
/// <summary>
/// 생성자
/// </summary>
/// <param name="writer">텍스트 라이터</param>
public RTFDocumentWriter(TextWriter writer)
{
this.colorTable.CheckValueExistWhenAdd = true;
Open(writer);
}
#endregion
#region 생성자 - RTFDocumentWriter(filePath)
/// <summary>
/// 생성자
/// </summary>
/// <param name="filePath">파일 경로</param>
public RTFDocumentWriter(string filePath)
{
this.colorTable.CheckValueExistWhenAdd = true;
Open(filePath);
}
#endregion
#region 생성자 - RTFDocumentWriter(stream)
/// <summary>
/// 생성자
/// </summary>
/// <param name="stream">스트림</param>
public RTFDocumentWriter(Stream stream)
{
this.colorTable.CheckValueExistWhenAdd = true;
StreamWriter writer = new StreamWriter(stream, Encoding.ASCII);
Open(writer);
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 열기 - Open(writer)
/// <summary>
/// 열기
/// </summary>
/// <param name="writer">텍스트 라이터</param>
/// <returns>처리 결과</returns>
public virtual bool Open(TextWriter writer)
{
this.writer = new RTFWriter(writer);
this.writer.Encoding = Encoding.GetEncoding(936);
this.writer.Indent = false;
return true;
}
#endregion
#region 열기 - Open(filePath)
/// <summary>
/// 열기
/// </summary>
/// <param name="filePath">파일 경로</param>
/// <returns>처리 결과</returns>
public virtual bool Open(string filePath)
{
this.writer = new RTFWriter(filePath);
this.writer.Encoding = Encoding.GetEncoding(936);
this.writer.Indent = false;
return true;
}
#endregion
#region 그룹 시작 쓰기 - WriteStartGroup()
/// <summary>
/// 그룹 시작 쓰기
/// </summary>
public void WriteStartGroup()
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteStartGroup();
}
}
#endregion
#region 그룹 종료 쓰기 - WriteEndGroup()
/// <summary>
/// 그룹 종료 쓰기
/// </summary>
public void WriteEndGroup()
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteEndGroup();
}
}
#endregion
#region 키워드 쓰기 - WriteKeyword(keyword)
/// <summary>
/// 키워드 쓰기
/// </summary>
/// <param name="keyword">키워드</param>
public void WriteKeyword(string keyword)
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteKeyword(keyword);
}
}
#endregion
#region 키워드 쓰기 - WriteKeyword(keyword, externKeyword)
/// <summary>
/// 키워드 쓰기
/// </summary>
/// <param name="keyword">키워드</param>
/// <param name="externKeyword">외부 키워드 여부</param>
public void WriteKeyword(string keyword, bool externKeyword)
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteKeyword(keyword, externKeyword);
}
}
#endregion
#region 원시 쓰기 - WriteRaw(text)
/// <summary>
/// 원시 쓰기
/// </summary>
/// <param name="text">텍스트</param>
public void WriteRaw(string text)
{
if(this.collectDocumentInfo == false)
{
if(text != null)
{
this.writer.WriteRaw(text);
}
}
}
#endregion
#region 테두리 쓰기 - WriteBorder(dashStyle)
/// <summary>
/// 테두리 쓰기
/// </summary>
/// <param name="dashStyle">대시 스타일</param>
public void WriteBorder(DashStyle dashStyle)
{
if(this.collectDocumentInfo == false)
{
if(dashStyle == DashStyle.Dot)
{
WriteKeyword("brdrdot");
}
else if(dashStyle == DashStyle.DashDot)
{
WriteKeyword("brdrdashd");
}
else if(dashStyle == DashStyle.DashDotDot)
{
WriteKeyword("brdrdashdd");
}
else if(dashStyle == DashStyle.Dash)
{
WriteKeyword("brdrdash");
}
else
{
WriteKeyword("brdrs");
}
}
}
#endregion
#region 문서 시작 쓰기 - WriteStartDocument()
/// <summary>
/// 문서 시작 쓰기
/// </summary>
public void WriteStartDocument()
{
this.lastParagraphInfo = null;
this.firstParagraph = true;
if(this.collectDocumentInfo)
{
this.documentInfoHashtable.Clear();
this.fontTable.Clear();
this.colorTable.Clear();
this.fontTable.Add(Control.DefaultFont.Name);
}
else
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword(RTFConstant.RTF);
this.writer.WriteKeyword("ansi");
this.writer.WriteKeyword($"ansicpg{this.writer.Encoding.CodePage}");
if(this.documentInfoHashtable.Count > 0)
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword("info");
foreach(string key in this.documentInfoHashtable.Keys)
{
this.writer.WriteStartGroup();
object value = this.documentInfoHashtable[key];
if(value is string)
{
this.writer.WriteKeyword(key);
this.writer.WriteText((string) value);
}
else if(value is int)
{
this.writer.WriteKeyword(key + value);
}
else if(value is DateTime)
{
DateTime dateTime = (DateTime)value;
this.writer.WriteKeyword(key);
this.writer.WriteKeyword("yr" + dateTime.Year );
this.writer.WriteKeyword("mo" + dateTime.Month );
this.writer.WriteKeyword("dy" + dateTime.Day );
this.writer.WriteKeyword("hr" + dateTime.Hour );
this.writer.WriteKeyword("min" + dateTime.Minute);
this.writer.WriteKeyword("sec" + dateTime.Second);
}
else
{
this.writer.WriteKeyword(key);
}
this.writer.WriteEndGroup();
}
this.writer.WriteEndGroup();
}
this.writer.WriteStartGroup();
this.writer.WriteKeyword(RTFConstant.FONTTBL);
for(int i = 0; i < this.fontTable.Count; i ++)
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword($"f{i}");
RTFFont font = this.fontTable[i];
this.writer.WriteText(font.Name);
if(font.CharacterSet != 1)
{
this.writer.WriteKeyword($"fcharset{font.CharacterSet}");
}
this.writer.WriteEndGroup();
}
this.writer.WriteEndGroup();
this.writer.WriteStartGroup();
this.writer.WriteKeyword(RTFConstant.COLORTBL);
this.writer.WriteRaw(";");
for(int i = 0; i < this.colorTable.Count; i++)
{
Color color = this.colorTable[i];
this.writer.WriteKeyword("red" + color.R);
this.writer.WriteKeyword("green" + color.G);
this.writer.WriteKeyword("blue" + color.B);
this.writer.WriteRaw(";");
}
this.writer.WriteEndGroup();
if(ListTable != null && ListTable.Count > 0)
{
if(DebugMode)
{
this.writer.WriteRaw(Environment.NewLine);
}
this.writer.WriteStartGroup();
this.writer.WriteKeyword("listtable", true);
foreach(RTFList list in ListTable)
{
if(DebugMode)
{
this.writer.WriteRaw(Environment.NewLine);
}
this.writer.WriteStartGroup();
this.writer.WriteKeyword("list");
this.writer.WriteKeyword($"listtemplateid{list.ListTemplateID}");
if(list.ListHybrid)
{
this.writer.WriteKeyword("listhybrid");
}
if(DebugMode)
{
this.writer.WriteRaw(Environment.NewLine);
}
this.writer.WriteStartGroup();
this.writer.WriteKeyword("listlevel");
this.writer.WriteKeyword($"levelfollow{list.LevelFollow}");
this.writer.WriteKeyword($"leveljc{list.JCLevel}");
this.writer.WriteKeyword($"levelstartat{list.LevelStartAt}");
this.writer.WriteKeyword($"levelnfc{Convert.ToInt32(list.NFCLevelNumberType)}");
this.writer.WriteKeyword($"levelnfcn{Convert.ToInt32(list.NFCLevelNumberType)}");
this.writer.WriteKeyword($"leveljc{list.JCLevel}");
if(string.IsNullOrEmpty(list.LevelText) == false)
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword("leveltext");
this.writer.WriteKeyword($"'0{list.LevelText.Length}");
if(list.NFCLevelNumberType == LevelNumberType.BULLET)
{
this.writer.WriteUnicodeText(list.LevelText);
}
else
{
this.writer.WriteText(list.LevelText, false);
}
this.writer.WriteEndGroup();
if(list.NFCLevelNumberType == LevelNumberType.BULLET)
{
RTFFont font = FontTable["Wingdings"];
if(font != null)
{
this.writer.WriteKeyword($"f{font.Index}");
}
}
else
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword("levelnumbers");
this.writer.WriteKeyword("'01");
this.writer.WriteEndGroup();
}
}
this.writer.WriteEndGroup();
this.writer.WriteKeyword($"listid{list.ListID}");
this.writer.WriteEndGroup();
}
this.writer.WriteEndGroup();
}
if(ListOverrideTable != null && ListOverrideTable.Count > 0)
{
if(DebugMode)
{
this.writer.WriteRaw(Environment.NewLine);
}
this.writer.WriteStartGroup();
this.writer.WriteKeyword("listoverridetable");
foreach(RTFListOverride listOverride in ListOverrideTable)
{
if(DebugMode)
{
this.writer.WriteRaw(Environment.NewLine);
}
this.writer.WriteStartGroup();
this.writer.WriteKeyword("listoverride");
this.writer.WriteKeyword($"listid{listOverride.ListID}");
this.writer.WriteKeyword($"listoverridecount{listOverride.ListOverriedCount}");
this.writer.WriteKeyword($"ls{listOverride.ID}");
this.writer.WriteEndGroup();
}
this.writer.WriteEndGroup();
}
if(DebugMode)
{
this.writer.WriteRaw(Environment.NewLine);
}
this.writer.WriteKeyword("viewkind1");
}
}
#endregion
#region 문서 종료 쓰기 - WriteEndDocument()
/// <summary>
/// 문서 종료 쓰기
/// </summary>
public void WriteEndDocument()
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteEndGroup();
}
this.writer.Flush();
}
#endregion
#region 머리글 시작 쓰기 - WriteStartHeader()
/// <summary>
/// 머리글 시작 쓰기
/// </summary>
public void WriteStartHeader()
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword("header");
}
}
#endregion
#region 머리글 종료 쓰기 - WriteEndHeader()
/// <summary>
/// 머리글 종료 쓰기
/// </summary>
public void WriteEndHeader()
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteEndGroup();
}
}
#endregion
#region 바닥글 시작 쓰기 - WriteStartFooter()
/// <summary>
/// 바닥글 시작 쓰기
/// </summary>
public void WriteStartFooter()
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword("footer");
}
}
#endregion
#region 바닥글 종료 쓰기 - WriteEndFooter()
/// <summary>
/// 바닥글 종료 쓰기
/// </summary>
public void WriteEndFooter()
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteEndGroup();
}
}
#endregion
#region 문단 시작 쓰기 - WriteStartParagraph()
/// <summary>
/// 문단 시작 쓰기
/// </summary>
public void WriteStartParagraph()
{
WriteStartParagraph(new RTFDocumentFormatInfo());
}
#endregion
#region 문단 시작 쓰기 - WriteStartParagraph(format)
/// <summary>
/// 문단 시작 쓰기
/// </summary>
/// <param name="format">문서 포맷 정보</param>
public void WriteStartParagraph(RTFDocumentFormatInfo format)
{
if(this.collectDocumentInfo)
{
}
else
{
if(this.firstParagraph)
{
this.firstParagraph = false;
this.writer.WriteRaw(Environment.NewLine);
}
else
{
this.writer.WriteKeyword("par");
}
if(format.ListID >= 0)
{
this.writer.WriteKeyword("pard");
this.writer.WriteKeyword($"ls{format.ListID}");
}
if(this.lastParagraphInfo != null)
{
if(this.lastParagraphInfo.ListID >= 0)
{
this.writer.WriteKeyword("pard");
}
}
switch(format.TextAlignment)
{
case RTFTextAlignment.LEFT :
this.writer.WriteKeyword("ql");
break;
case RTFTextAlignment.CENTER :
this.writer.WriteKeyword("qc");
break;
case RTFTextAlignment.RIGHT :
this.writer.WriteKeyword("qr");
break;
case RTFTextAlignment.JUSTIFY :
this.writer.WriteKeyword("qj");
break;
}
if(format.ParagraphFirstLineIndent != 0)
{
this.writer.WriteKeyword($"fi{Convert.ToInt32(format.ParagraphFirstLineIndent * 400 / format.StandTabWidth)}");
}
else
{
this.writer.WriteKeyword("fi0");
}
if(format.LeftIndent != 0)
{
this.writer.WriteKeyword($"li{Convert.ToInt32(format.LeftIndent * 400 / format.StandTabWidth)}");
}
else
{
this.writer.WriteKeyword("li0");
}
this.writer.WriteKeyword("plain");
}
this.lastParagraphInfo = format ;
}
#endregion
#region 문단 종료 쓰기 - WriteEndParagraph()
/// <summary>
/// 문단 종료 쓰기
/// </summary>
public void WriteEndParagraph()
{
}
#endregion
#region 텍스트 쓰기 - WriteText(text)
/// <summary>
/// 텍스트 쓰기
/// </summary>
/// <param name="text">텍스트</param>
public void WriteText(string text)
{
if(text != null && this.collectDocumentInfo == false)
{
this.writer.WriteText(text);
}
}
#endregion
#region 폰트 쓰기 - WriteFont(font)
/// <summary>
/// 폰트 쓰기
/// </summary>
/// <param name="font">폰트</param>
public void WriteFont(Font font)
{
if(font == null)
{
throw new ArgumentNullException("font");
}
if(this.collectDocumentInfo)
{
this.fontTable.Add(font.Name);
}
else
{
int index = this.fontTable.GetIndex(font.Name);
if(index >= 0)
{
this.writer.WriteKeyword($"f{index}");
}
if(font.Bold)
{
this.writer.WriteKeyword("b");
}
if(font.Italic)
{
this.writer.WriteKeyword("i");
}
if(font.Underline)
{
this.writer.WriteKeyword("ul");
}
if(font.Strikeout)
{
this.writer.WriteKeyword("strike");
}
this.writer.WriteKeyword($"fs{Convert.ToInt32(font.Size * 2)}");
}
}
#endregion
#region 문자열 시작 쓰기 - WriteStartString(format)
/// <summary>
/// 문자열 시작 쓰기
/// </summary>
/// <param name="format">문서 포맷 정보</param>
public void WriteStartString(RTFDocumentFormatInfo format)
{
if(this.collectDocumentInfo)
{
this.fontTable.Add(format.FontName);
this.colorTable.Add(format.TextColor);
this.colorTable.Add(format.BackgroundColor);
if(format.BorderColor.A != 0)
{
this.colorTable.Add(format.BorderColor);
}
return;
}
if(format.Link != null && format.Link.Length > 0)
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword("field");
this.writer.WriteStartGroup();
this.writer.WriteKeyword("fldinst", true);
this.writer.WriteStartGroup();
this.writer.WriteKeyword("hich");
this.writer.WriteText($" HYPERLINK \"{format.Link}\"");
this.writer.WriteEndGroup();
this.writer.WriteEndGroup();
this.writer.WriteStartGroup();
this.writer.WriteKeyword("fldrslt");
this.writer.WriteStartGroup();
}
switch(format.TextAlignment)
{
case RTFTextAlignment.LEFT :
this.writer.WriteKeyword("ql");
break;
case RTFTextAlignment.CENTER :
this.writer.WriteKeyword("qc");
break;
case RTFTextAlignment.RIGHT :
this.writer.WriteKeyword("qr");
break;
case RTFTextAlignment.JUSTIFY :
this.writer.WriteKeyword("qj");
break;
}
this.writer.WriteKeyword("plain");
int index = this.fontTable.GetIndex(format.FontName);
if(index >= 0)
{
this.writer.WriteKeyword($"f{index}");
}
if(format.Bold)
{
this.writer.WriteKeyword("b");
}
if(format.Italic)
{
this.writer.WriteKeyword("i");
}
if(format.Underline)
{
this.writer.WriteKeyword("ul");
}
if(format.Strikeout)
{
this.writer.WriteKeyword("strike");
}
this.writer.WriteKeyword($"fs{Convert.ToInt32(format.FontSize * 2)}");
index = this.colorTable.GetIndex(format.BackgroundColor);
if(index >= 0)
{
this.writer.WriteKeyword($"chcbpat{Convert.ToString(index + 1)}");
}
index = this.colorTable.GetIndex(format.TextColor);
if(index >= 0)
{
this.writer.WriteKeyword($"cf{Convert.ToString(index + 1)}");
}
if(format.Subscript)
{
this.writer.WriteKeyword("sub");
}
if(format.Superscript)
{
this.writer.WriteKeyword("super");
}
if(format.NoWrap)
{
this.writer.WriteKeyword("nowwrap");
}
if(format.LeftBorder || format.TopBorder || format.RightBorder || format.BottomBorder)
{
if(format.BorderColor.A != 0)
{
this.writer.WriteKeyword("chbrdr" );
this.writer.WriteKeyword("brdrs" );
this.writer.WriteKeyword("brdrw10");
index = this.colorTable.GetIndex(format.BorderColor);
if(index >= 0)
{
this.writer.WriteKeyword($"brdrcf{Convert.ToString(index + 1)}");
}
}
}
}
#endregion
#region 문자열 종료 쓰기 - WriteEndString(format)
/// <summary>
/// 문자열 종료 쓰기
/// </summary>
/// <param name="format">문서 포맷 정보</param>
public void WriteEndString(RTFDocumentFormatInfo format)
{
if(this.collectDocumentInfo)
{
return ;
}
if(format.Subscript)
{
this.writer.WriteKeyword("sub0");
}
if(format.Superscript)
{
this.writer.WriteKeyword("super0");
}
if(format.Bold)
{
this.writer.WriteKeyword("b0");
}
if(format.Italic)
{
this.writer.WriteKeyword("i0");
}
if(format.Underline)
{
this.writer.WriteKeyword("ul0");
}
if(format.Strikeout)
{
this.writer.WriteKeyword("strike0");
}
if(format.Link != null && format.Link.Length > 0)
{
this.writer.WriteEndGroup();
this.writer.WriteEndGroup();
this.writer.WriteEndGroup();
}
}
#endregion
#region 문자열 쓰기 - WriteString(text , format)
/// <summary>
/// 문자열 쓰기
/// </summary>
/// <param name="text">텍스트</param>
/// <param name="format">문서 포맷 정보</param>
public void WriteString(string text , RTFDocumentFormatInfo format)
{
if(this.collectDocumentInfo)
{
this.fontTable.Add(format.FontName);
this.colorTable.Add(format.TextColor);
this.colorTable.Add(format.BackgroundColor);
}
else
{
this.WriteStartString(format);
if(format.MultiLine)
{
if(text != null)
{
text = text.Replace("\n", string.Empty);
StringReader reader = new StringReader(text);
string line = reader.ReadLine();
int i = 0 ;
while(line != null)
{
if(i > 0)
{
this.writer.WriteKeyword("line");
}
i++;
this.writer.WriteText(line);
line = reader.ReadLine();
}
reader.Close();
}
}
else
{
this.writer.WriteText(text);
}
this.WriteEndString(format);
}
}
#endregion
#region 북마크 시작 쓰기 - WriteStartBookmark(bookmarkName)
/// <summary>
/// 북마크 시작 쓰기
/// </summary>
/// <param name="bookmarkName">북마크명</param>
public void WriteStartBookmark(string bookmarkName)
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteStartGroup();
this.writer.WriteKeyword("bkmkstart" , true);
this.writer.WriteKeyword("f0");
this.writer.WriteText(bookmarkName);
this.writer.WriteEndGroup();
this.writer.WriteStartGroup();
this.writer.WriteKeyword("bkmkend" , true);
this.writer.WriteKeyword("f0");
this.writer.WriteText(bookmarkName);
this.writer.WriteEndGroup();
}
}
#endregion
#region 라인 브레이크 쓰기 - WriteLineBreak()
/// <summary>
/// 라인 브레이크 쓰기
/// </summary>
public void WriteLineBreak()
{
if(this.collectDocumentInfo == false)
{
this.writer.WriteKeyword("line");
}
}
#endregion
#region 이미지 쓰기 - WriteImage(image, width, height, imageByteArray)
/// <summary>
/// 이미지 쓰기
/// </summary>
/// <param name="image">이미지</param>
/// <param name="width">너비</param>
/// <param name="height">높이</param>
/// <param name="imageByteArray">이미지 바이트 배열</param>
public void WriteImage(Image image, int width, int height, byte[] imageByteArray)
{
if(this.collectDocumentInfo)
{
return;
}
else
{
if(imageByteArray == null)
{
return;
}
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Jpeg);
memoryStream.Close();
byte[] byteArray = memoryStream.ToArray();
this.writer.WriteStartGroup();
this.writer.WriteKeyword("pict");
this.writer.WriteKeyword("jpegblip");
this.writer.WriteKeyword($"picscalex{Convert.ToInt32(width * 100.0 / image.Size.Width )}");
this.writer.WriteKeyword($"picscaley{Convert.ToInt32(height * 100.0 / image.Size.Height)}");
this.writer.WriteKeyword($"picwgoal{Convert.ToString(image.Size.Width * 15)}");
this.writer.WriteKeyword($"pichgoal{Convert.ToString(image.Size.Height * 15)}");
this.writer.WriteByteArray(byteArray);
this.writer.WriteEndGroup();
}
}
#endregion
#region 닫기 - Close()
/// <summary>
/// 닫기
/// </summary>
public virtual void Close()
{
this.writer.Close();
}
#endregion
}
}
▶ RTFDOMBookmark.cs
using System;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 북마크
/// </summary>
[Serializable]
public class RTFDOMBookmark : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 명칭
/// </summary>
private string name = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 명칭 - Name
/// <summary>
/// 명칭
/// </summary>
[DefaultValue( null )]
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMBookmark()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMBookmark()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return "BookMark:" + this.name;
}
#endregion
}
}
▶ RTFDOMDocument.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 문서
/// </summary>
public partial class RTFDOMDocument : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Event
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 진행시 이벤트 - Progress
/// <summary>
/// 진행시 이벤트
/// </summary>
public event ProgressEventHandler Progress = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 디폴트 폰트명
/// </summary>
private static string _defaultFontName = Control.DefaultFont.Name;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 문자 추종 여부
/// </summary>
private string followingCharacters = null;
/// <summary>
/// 문자 리딩
/// </summary>
private string leadingCharacters = null;
/// <summary>
/// 디폴트 인코딩
/// </summary>
private Encoding defaultEncoding = Encoding.Default;
/// <summary>
/// 폰트 문자 세트 인코딩
/// </summary>
private Encoding fontChartSetEncoding = null;
/// <summary>
/// 연관 폰트 문자 세트 인코딩
/// </summary>
private Encoding associateFontChartSetEncoding = null;
/// <summary>
/// 폰트 테이블
/// </summary>
private RTFFontTable fontTable = new RTFFontTable();
/// <summary>
/// 색상 테이블
/// </summary>
private RTFColorTable colorTable = new RTFColorTable();
/// <summary>
/// 리스트 테이블
/// </summary>
private RTFListTable listTable = new RTFListTable();
/// <summary>
/// 리스트 오버라이드 테이블
/// </summary>
private RTFListOverrideTable listOverrideTable = new RTFListOverrideTable();
/// <summary>
/// 문서 정보
/// </summary>
private RTFDocumentInfo documentInfo = new RTFDocumentInfo();
/// <summary>
/// 제너레이터
/// </summary>
private string generator = null;
/// <summary>
/// 페이퍼 너비
/// </summary>
private int paperWidth = 12240;
/// <summary>
/// 페이퍼 높이
/// </summary>
private int paperHeight = 15840;
/// <summary>
/// 왼쪽 마진
/// </summary>
private int leftMargin = 1800;
/// <summary>
/// 위쪽 마진
/// </summary>
private int topMargin = 1440;
/// <summary>
/// 오른쪽 마진
/// </summary>
private int rightMargin = 1800;
/// <summary>
/// 아래쪽 마진
/// </summary>
private int bottomMargin = 1440;
/// <summary>
/// 가로 여부
/// </summary>
private bool landscape = false;
/// <summary>
/// 머리글 거리
/// </summary>
private int headerDistance = 720;
/// <summary>
/// 바닥글 거리
/// </summary>
private int footerDistance = 720;
/// <summary>
/// Times New Roman 변경 여부
/// </summary>
private bool changeTimesNewRoman = false;
/// <summary>
/// 디폴트 행 높이
/// </summary>
private int defaultRowHeight = 400;
/// <summary>
/// HTML 컨텐트
/// </summary>
private string htmlContent = null;
/// <summary>
/// 컨텐트 시작 여부
/// </summary>
private bool startContent = false;
/// <summary>
/// 토큰 카운트
/// </summary>
private int tokenCount = 0;
/// <summary>
/// 문단 문서 포맷 정보
/// </summary>
private RTFDocumentFormatInfo paragraphFormat = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자 추종 여부 - FollowingCharacters
/// <summary>
/// 문자 추종 여부
/// </summary>
[DefaultValue(null)]
public string FollowingCharacters
{
get
{
return this.followingCharacters;
}
set
{
this.followingCharacters = value;
}
}
#endregion
#region 문자 리딩 - LeadingCharacters
/// <summary>
/// 문자 리딩
/// </summary>
[DefaultValue(null)]
public string LeadingCharacters
{
get
{
return this.leadingCharacters;
}
set
{
this.leadingCharacters = value;
}
}
#endregion
#region 폰트 테이블 - FontTable
/// <summary>
/// 폰트 테이블
/// </summary>
public RTFFontTable FontTable
{
get
{
return this.fontTable;
}
set
{
this.fontTable = value;
}
}
#endregion
#region 색상 테이블 - ColorTable
/// <summary>
/// 색상 테이블
/// </summary>
public RTFColorTable ColorTable
{
get
{
return this.colorTable;
}
set
{
this.colorTable = value;
}
}
#endregion
#region 리스트 테이블 - ListTable
/// <summary>
/// 리스트 테이블
/// </summary>
public RTFListTable ListTable
{
get
{
return this.listTable;
}
set
{
this.listTable = value;
}
}
#endregion
#region 리스트 오버라이드 테이블 - ListOverrideTable
/// <summary>
/// 리스트 오버라이드 테이블
/// </summary>
public RTFListOverrideTable ListOverrideTable
{
get
{
return this.listOverrideTable;
}
set
{
this.listOverrideTable = value;
}
}
#endregion
#region 문서 정보 - DocumentInfo
/// <summary>
/// 문서 정보
/// </summary>
public RTFDocumentInfo DocumentInfo
{
get
{
return this.documentInfo;
}
set
{
this.documentInfo = value;
}
}
#endregion
#region 제너레이터 - Generator
/// <summary>
/// 제너레이터
/// </summary>
[DefaultValue(null)]
public string Generator
{
get
{
return this.generator;
}
set
{
this.generator = value;
}
}
#endregion
#region 페이퍼 너비 - PaperWidth
/// <summary>
/// 페이퍼 너비
/// </summary>
[DefaultValue(12240)]
public int PaperWidth
{
get
{
return this.paperWidth;
}
set
{
this.paperWidth = value;
}
}
#endregion
#region 페이퍼 높이 - PaperHeight
/// <summary>
/// 페이퍼 높이
/// </summary>
[DefaultValue(15840)]
public int PaperHeight
{
get
{
return this.paperHeight;
}
set
{
this.paperHeight = value;
}
}
#endregion
#region 왼쪽 마진 - LeftMargin
/// <summary>
/// 왼쪽 마진
/// </summary>
[DefaultValue(1800)]
public int LeftMargin
{
get
{
return this.leftMargin;
}
set
{
this.leftMargin = value;
}
}
#endregion
#region 위쪽 마진 - TopMargin
/// <summary>
/// 위쪽 마진
/// </summary>
[DefaultValue(1440)]
public int TopMargin
{
get
{
return this.topMargin;
}
set
{
this.topMargin = value;
}
}
#endregion
#region 오른쪽 마진 - RightMargin
/// <summary>
/// 오른쪽 마진
/// </summary>
[DefaultValue(1800)]
public int RightMargin
{
get
{
return this.rightMargin;
}
set
{
this.rightMargin = value;
}
}
#endregion
#region 아래쪽 마진 - BottomMargin
/// <summary>
/// 아래쪽 마진
/// </summary>
[DefaultValue(1440)]
public int BottomMargin
{
get
{
return this.bottomMargin;
}
set
{
this.bottomMargin = value;
}
}
#endregion
#region 가로 여부 - Landscape
/// <summary>
/// 가로 여부
/// </summary>
[DefaultValue(false)]
public bool Landscape
{
get
{
return this.landscape;
}
set
{
this.landscape = value;
}
}
#endregion
#region 머리글 거리 - HeaderDistance
/// <summary>
/// 머리글 거리
/// </summary>
[DefaultValue(720)]
public int HeaderDistance
{
get
{
return this.headerDistance;
}
set
{
this.headerDistance = value;
}
}
#endregion
#region 바닥글 거리 - FooterDistance
/// <summary>
/// 바닥글 거리
/// </summary>
[DefaultValue(720)]
public int FooterDistance
{
get
{
return this.footerDistance;
}
set
{
this.footerDistance = value;
}
}
#endregion
#region 클라이언트 영역 너비 - ClientAreaWidth
/// <summary>
/// 클라이언트 영역 너비
/// </summary>
[Browsable(false)]
public int ClientAreaWidth
{
get
{
if(this.landscape)
{
return this.paperHeight - this.leftMargin - this.rightMargin;
}
else
{
return this.paperWidth - this.leftMargin - this.rightMargin;
}
}
}
#endregion
#region Times New Roman 변경 여부 - ChangeTimesNewRoman
/// <summary>
/// Times New Roman 변경 여부
/// </summary>
[DefaultValue(true)]
public bool ChangeTimesNewRoman
{
get
{
return this.changeTimesNewRoman;
}
set
{
this.changeTimesNewRoman = value;
}
}
#endregion
#region 디폴트 행 높이 - DefaultRowHeight
/// <summary>
/// 디폴트 행 높이
/// </summary>
public int DefaultRowHeight
{
get
{
return this.defaultRowHeight;
}
set
{
this.defaultRowHeight = value;
}
}
#endregion
#region HTML 컨텐트 - HTMLContent
/// <summary>
/// HTML 컨텐트
/// </summary>
public string HTMLContent
{
get
{
return this.htmlContent;
}
set
{
this.htmlContent = value;
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region 실행시 인코딩 - RuntimeEncoding
/// <summary>
/// 실행시 인코딩
/// </summary>
internal Encoding RuntimeEncoding
{
get
{
if(this.fontChartSetEncoding != null)
{
return this.fontChartSetEncoding;
}
if(this.associateFontChartSetEncoding != null)
{
return this.associateFontChartSetEncoding;
}
return this.defaultEncoding;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMDocument()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMDocument()
{
OwnerDocument = this;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 로드하기 - Load(stream)
/// <summary>
/// 로드하기
/// </summary>
/// <param name="stream">스트림</param>
public void Load(Stream stream)
{
this.htmlContent = null;
ElementList.Clear();
this.startContent = false;
RTFReader reader = new RTFReader(stream);
RTFDocumentFormatInfo format = new RTFDocumentFormatInfo();
this.paragraphFormat = null;
Load(reader, format);
CombinTable(this);
FixElements(this);
}
#endregion
#region 로드하기 - Load(filePath)
/// <summary>
/// 로드하기
/// </summary>
/// <param name="filePath">파일 경로</param>
public void Load(string filePath)
{
using(FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
Load(stream);
}
}
#endregion
#region 로드하기 - Load(textReader)
/// <summary>
/// 로드하기
/// </summary>
/// <param name="textReader">텍스트 리더</param>
public void Load(TextReader textReader)
{
this.htmlContent = null;
ElementList.Clear();
this.startContent = false;
RTFReader rtfReader = new RTFReader(textReader);
RTFDocumentFormatInfo format = new RTFDocumentFormatInfo();
this.paragraphFormat = null;
Load(rtfReader, format);
CombinTable(this);
FixElements(this);
}
#endregion
#region RTF 텍스트 로드하기 - LoadRTFText(rtf)
/// <summary>
/// RTF 텍스트 로드하기
/// </summary>
/// <param name="rtf">RTF</param>
public void LoadRTFText(string rtf)
{
StringReader stringReader = new StringReader(rtf);
this.htmlContent = null;
ElementList.Clear();
this.startContent = false;
RTFReader rtfReader = new RTFReader(stringReader);
RTFDocumentFormatInfo format = new RTFDocumentFormatInfo();
this.paragraphFormat = null;
Load(rtfReader, format);
CombinTable(this);
FixElements(this);
}
#endregion
#region 마지막 엘리먼트 구하기 - GetLastElement()
/// <summary>
/// 마지막 엘리먼트 구하기
/// </summary>
/// <returns>마지막 엘리먼트</returns>
public RTFDOMElement GetLastElement()
{
RTFDOMElement[] lastElementArray = GetLastElementArray(true);
return lastElementArray[lastElementArray.Length - 1];
}
#endregion
#region 마지막 엘리먼트 구하기 - GetLastElement(elementType)
/// <summary>
/// 마지막 엘리먼트 구하기
/// </summary>
/// <param name="elementType">엘리먼트 타입</param>
/// <returns>마지막 엘리먼트</returns>
public RTFDOMElement GetLastElement(Type elementType)
{
RTFDOMElement[] lastElementArray = GetLastElementArray(true);
for(int i = lastElementArray.Length - 1; i >= 0; i--)
{
if(elementType.IsInstanceOfType(lastElementArray[i]))
{
return lastElementArray[i];
}
}
return null;
}
#endregion
#region 마지막 엘리먼트 구하기 - GetLastElement(elementType, lockStatus)
/// <summary>
/// 마지막 엘리먼트 구하기
/// </summary>
/// <param name="elementType">엘리먼트 타입</param>
/// <param name="lockStatus">상태 잠금 여부</param>
/// <returns>마지막 엘리먼트</returns>
public RTFDOMElement GetLastElement(Type elementType, bool lockStatus)
{
RTFDOMElement[] laseElementArray = GetLastElementArray(true);
for(int i = laseElementArray.Length - 1; i >= 0; i--)
{
if(elementType.IsInstanceOfType(laseElementArray[i]))
{
if(laseElementArray[i].Locked == lockStatus)
{
return laseElementArray[i];
}
}
}
return null;
}
#endregion
#region DOM 문자열 구하기 - GetDOMString()
/// <summary>
/// DOM 문자열 구하기
/// </summary>
/// <returns>DOM 문자열</returns>
public override string GetDOMString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(ToString());
stringBuilder.Append(Environment.NewLine + " Info");
foreach(string item in this.documentInfo.ItemArray)
{
stringBuilder.Append(Environment.NewLine + " " + item);
}
stringBuilder.Append(Environment.NewLine + " ColorTable(" + this.colorTable.Count + ")");
for(int i = 0; i < this.colorTable.Count; i ++)
{
Color color = this.colorTable[i];
stringBuilder.Append(Environment.NewLine + " " + i + ":" + color.R + " " + color.G + " " + color.B);
}
stringBuilder.Append(Environment.NewLine + " FontTable(" + this.fontTable.Count + ")");
foreach(RTFFont font in this.fontTable)
{
stringBuilder.Append(Environment.NewLine + " " + font.ToString());
}
if(this.listTable.Count > 0)
{
stringBuilder.Append(Environment.NewLine + " ListTable(" + this.listTable.Count + ")");
foreach(RTFList list in this.listTable)
{
stringBuilder.Append(Environment.NewLine + " " + list.ToString());
}
}
if(this.ListOverrideTable.Count > 0)
{
stringBuilder.Append(Environment.NewLine + " ListOverrideTable(" + ListOverrideTable.Count + ")");
foreach(RTFListOverride list in ListOverrideTable)
{
stringBuilder.Append(Environment.NewLine + " " + list.ToString());
}
}
stringBuilder.Append(Environment.NewLine + " -----------------------");
if(string.IsNullOrEmpty(this.HTMLContent) == false)
{
stringBuilder.Append(Environment.NewLine + " HTMLContent:" + HTMLContent);
stringBuilder.Append(Environment.NewLine + " -----------------------");
}
GetDOMString(ElementList, stringBuilder, 1);
return stringBuilder.ToString();
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 진행시 이벤트 발생시키기 - FireProgressEvent(maximumValue, value, message)
/// <summary>
/// 진행시 이벤트 발생시키기
/// </summary>
/// <param name="maximumValue">최대 값</param>
/// <param name="value">값</param>
/// <param name="message">메시지</param>
/// <returns>처리 결과</returns>
protected bool FireProgressEvent(int maximumValue, int value, string message)
{
if(Progress != null)
{
ProgressEventArgs e = new ProgressEventArgs(maximumValue, value, message);
Progress(this, e);
return e.Cancel;
}
return false;
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 엘리먼트 수정하기 - FixElements(parentElement)
/// <summary>
/// 엘리먼트 수정하기
/// </summary>
/// <param name="parentElement">부모 엘리먼트</param>
private void FixElements(RTFDOMElement parentElement)
{
ArrayList arrayList = new ArrayList();
foreach(RTFDOMElement element in parentElement.ElementList)
{
if(element is RTFDOMParagraph)
{
RTFDOMParagraph paragraph = (RTFDOMParagraph)element;
if(paragraph.Format.PageBreak)
{
paragraph.Format.PageBreak = false;
arrayList.Add(new RTFDOMPageBreak());
}
}
if(element is RTFDOMText)
{
if(arrayList.Count > 0 && arrayList[arrayList.Count - 1] is RTFDOMText)
{
RTFDOMText lastText = (RTFDOMText)arrayList[arrayList.Count - 1];
RTFDOMText text = (RTFDOMText)element;
if(lastText.Text.Length == 0 || text.Text.Length == 0)
{
if(lastText.Text.Length == 0)
{
lastText.Format = text.Format.Clone();
}
lastText.Text = lastText.Text + text.Text;
}
else
{
if(lastText.Format.EqualsSettings(text.Format))
{
lastText.Text = lastText.Text + text.Text;
}
else
{
arrayList.Add(text);
}
}
}
else
{
arrayList.Add(element);
}
}
else
{
arrayList.Add(element);
}
}
parentElement.ElementList.Clear();
parentElement.Locked = false;
foreach(RTFDOMElement element in arrayList)
{
parentElement.AppendChild(element);
}
foreach(RTFDOMElement element in parentElement.ElementList.ToArray())
{
if(element is RTFDOMTable)
{
UpdateTableCells((RTFDOMTable)element, true);
}
}
foreach(RTFDOMElement element in parentElement.ElementList)
{
FixElements(element);
}
}
#endregion
#region 마지막 엘리먼트 배열 구하기 - GetLastElementArray(checkLockState)
/// <summary>
/// 마지막 엘리먼트 배열 구하기
/// </summary>
/// <param name="checkLockState">상태 잠금 체크 여부</param>
/// <returns>엘리먼트 배열</returns>
private RTFDOMElement[] GetLastElementArray(bool checkLockState)
{
List<RTFDOMElement> targetList = new List<RTFDOMElement>();
RTFDOMElement element = this;
while(element != null)
{
if(checkLockState)
{
if(element.Locked)
{
break;
}
}
targetList.Add(element);
element = element.ElementList.LastElement;
}
if(checkLockState)
{
for(int i = targetList.Count - 1; i >= 0; i--)
{
if(targetList[i].Locked)
{
targetList.RemoveAt(i);
}
}
}
return targetList.ToArray();
}
#endregion
#region 문단 완료하기 - CompleteParagraph()
/// <summary>
/// 문단 완료하기
/// </summary>
private void CompleteParagraph()
{
RTFDOMElement lastElement = GetLastElement();
while(lastElement != null)
{
if(lastElement is RTFDOMParagraph)
{
RTFDOMParagraph paragraph = (RTFDOMParagraph)lastElement;
paragraph.Locked = true;
if(this.paragraphFormat != null)
{
paragraph.Format = this.paragraphFormat;
this.paragraphFormat = this.paragraphFormat.Clone();
}
else
{
this.paragraphFormat = new RTFDocumentFormatInfo();
}
break;
}
lastElement = lastElement.ParentElement;
}
}
#endregion
#region 컨텐트 엘리먼트 추가하기 - AddContentElement(newElement)
/// <summary>
/// 컨텐트 엘리먼트 추가하기
/// </summary>
/// <param name="newElement">신규 엘리먼트</param>
private void AddContentElement(RTFDOMElement newElement)
{
RTFDOMElement[] lastElementArray = GetLastElementArray(true);
RTFDOMElement lastElement = null;
if(lastElementArray.Length > 0)
{
lastElement = lastElementArray[lastElementArray.Length - 1];
}
if(lastElement is RTFDOMDocument || lastElement is RTFDOMHeader || lastElement is RTFDOMFooter)
{
if
(
newElement is RTFDOMText ||
newElement is RTFDOMImage ||
newElement is RTFDOMObject ||
newElement is RTFDOMShape ||
newElement is RTFDOMShapeGroup
)
{
RTFDOMParagraph paragraph = new RTFDOMParagraph();
if(lastElement.ElementList.Count > 0)
{
paragraph.isTemplateGenerated = true;
}
if(this.paragraphFormat != null)
{
paragraph.Format = this.paragraphFormat;
}
lastElement.AppendChild(paragraph);
paragraph.ElementList.Add(newElement);
return;
}
}
RTFDOMElement element1 = lastElementArray[lastElementArray.Length - 1];
if(newElement != null && newElement.NativeLevel > 0)
{
for(int i = lastElementArray.Length - 1; i >= 0; i--)
{
if(lastElementArray[i].NativeLevel == newElement.NativeLevel)
{
for(int j = i; j < lastElementArray.Length; j++)
{
RTFDOMElement element2 = lastElementArray[j];
if
(
newElement is RTFDOMText ||
newElement is RTFDOMImage ||
newElement is RTFDOMObject ||
newElement is RTFDOMShape ||
newElement is RTFDOMShapeGroup ||
newElement is RTFDOMField ||
newElement is RTFDOMBookmark ||
newElement is RTFDOMLineBreak
)
{
if(newElement.NativeLevel == element2.NativeLevel)
{
if
(
element2 is RTFDOMTableRow ||
element2 is RTFDOMTableCell ||
element2 is RTFDOMField ||
element2 is RTFDOMParagraph
)
{
continue;
}
}
}
lastElementArray[j].Locked = true;
}
break;
}
}
}
for(int i = lastElementArray.Length - 1; i >= 0; i--)
{
if(lastElementArray[i].Locked == false)
{
element1 = lastElementArray[i];
if(element1 is RTFDOMImage)
{
element1.Locked = true;
}
else
{
break;
}
}
}
if(element1 is RTFDOMTableRow)
{
RTFDOMTableCell cell = new RTFDOMTableCell();
cell.NativeLevel = element1.NativeLevel;
element1.AppendChild(cell);
if(newElement is RTFDOMTableRow)
{
cell.ElementList.Add(newElement);
}
else
{
RTFDOMParagraph cellParagraph = new RTFDOMParagraph();
cellParagraph.Format = this.paragraphFormat.Clone();
cellParagraph.NativeLevel = cell.NativeLevel;
cell.AppendChild(cellParagraph);
if(newElement != null)
{
cellParagraph.AppendChild(newElement);
}
}
}
else
{
if(newElement != null)
{
if(element1 is RTFDOMParagraph && (newElement is RTFDOMParagraph || newElement is RTFDOMTableRow))
{
element1.Locked = true;
element1.ParentElement.AppendChild(newElement);
}
else
{
element1.AppendChild(newElement);
}
}
}
}
#endregion
#region 바이트 배열 구하기 - GetByteArray(hexadecimal)
/// <summary>
/// 바이트 배열 구하기
/// </summary>
/// <param name="hexadecimal">16진수 문자열</param>
/// <returns>바이트 배열</returns>
private byte[] GetByteArray(string hexadecimal)
{
string characterList = "0123456789abcdef";
int index = 0;
int value = 0;
int characterCount = 0;
ByteBuffer buffer = new ByteBuffer();
for(int i = 0; i < hexadecimal.Length; i++)
{
char character = hexadecimal[i];
character = char.ToLower(character);
index = characterList.IndexOf(character);
if(index >= 0)
{
characterCount++;
value = value * 16 + index;
if(characterCount > 0 && (characterCount % 2) == 0)
{
buffer.Add((byte)value);
value = 0;
}
}
}
return buffer.ToArray();
}
#endregion
#region 테이블 결합하기 - CombinTable(parentElement)
/// <summary>
/// 테이블 결합하기
/// </summary>
/// <param name="parentElement">부모 엘리먼트</param>
private void CombinTable(RTFDOMElement parentElement)
{
ArrayList targetList = new ArrayList();
ArrayList rowList = new ArrayList();
int lastRowWidth = -1;
RTFDOMTableRow lastRow = null;
foreach(RTFDOMElement element in parentElement.ElementList)
{
if(element is RTFDOMTableRow)
{
RTFDOMTableRow row = (RTFDOMTableRow)element;
row.Locked = false;
ArrayList cellSettingList = row.CellSettingList;
if(cellSettingList.Count == 0)
{
if(lastRow != null && lastRow.CellSettingList.Count == row.ElementList.Count)
{
cellSettingList = lastRow.CellSettingList;
}
}
if(cellSettingList.Count == row.ElementList.Count)
{
for(int i = 0; i < row.ElementList.Count; i++)
{
row.ElementList[i].AttributeList = (RTFAttributeList)cellSettingList[i];
}
}
bool isLastRow = row.HasAttribute(RTFConstant.LASTROW);
if(isLastRow == false)
{
int index = parentElement.ElementList.GetIndex(element);
if(index == parentElement.ElementList.Count - 1)
{
isLastRow = true;
}
else
{
RTFDOMElement childElement = parentElement.ElementList[index + 1];
if(!(childElement is RTFDOMTableRow))
{
isLastRow = true;
}
}
}
if(isLastRow)
{
rowList.Add(row);
targetList.Add(CreateTable(rowList));
lastRowWidth = -1;
}
else
{
int width = 0;
if(row.HasAttribute(RTFConstant.TRWWIDTH))
{
width = row.AttributeList[RTFConstant.TRWWIDTH];
if(row.HasAttribute(RTFConstant.TRWWIDTHA))
{
width = width - row.AttributeList[RTFConstant.TRWWIDTHA];
}
}
else
{
foreach(RTFDOMTableCell cell in row.ElementList)
{
if(cell.HasAttribute(RTFConstant.CELLX))
{
width = Math.Max(width, cell.AttributeList[RTFConstant.CELLX]);
}
}
}
if(lastRowWidth > 0 && lastRowWidth != width)
{
if(rowList.Count > 0)
{
targetList.Add(CreateTable(rowList));
}
}
lastRowWidth = width;
rowList.Add(row);
}
lastRow = row;
}
else if(element is RTFDOMTableCell)
{
lastRow = null;
CombinTable(element);
if(rowList.Count > 0)
{
targetList.Add(CreateTable(rowList));
}
targetList.Add(element);
lastRowWidth = -1;
}
else
{
lastRow = null;
CombinTable(element);
if(rowList.Count > 0)
{
targetList.Add(CreateTable(rowList));
}
targetList.Add(element);
lastRowWidth = -1;
}
}
if(rowList.Count > 0)
{
targetList.Add(CreateTable(rowList));
}
parentElement.Locked = false;
parentElement.ElementList.Clear();
foreach(RTFDOMElement element in targetList)
{
parentElement.AppendChild(element);
}
}
#endregion
#region 테이블 생성하기 - CreateTable(rowList)
/// <summary>
/// 테이블 생성하기
/// </summary>
/// <param name="rowList">행 리스트</param>
/// <returns>테이블</returns>
private RTFDOMTable CreateTable(ArrayList rowList)
{
if(rowList.Count > 0)
{
RTFDOMTable table = new RTFDOMTable();
int index = 0;
foreach(RTFDOMTableRow row in rowList)
{
row.RowIndex = index;
index++;
table.AppendChild(row);
}
rowList.Clear();
foreach(RTFDOMTableRow row in table.ElementList)
{
foreach(RTFDOMTableCell cell in row.ElementList)
{
CombinTable(cell);
}
}
return table;
}
else
{
throw new ArgumentException("rowList");
}
}
#endregion
#region 테이블 셀 업데이트하기 - UpdateTableCells(table, fixTableCellSize)
/// <summary>
/// 테이블 셀 업데이트하기
/// </summary>
/// <param name="table">테이블</param>
/// <param name="fixTableCellSize">테이블 셀 크기 수정 여부</param>
private void UpdateTableCells(RTFDOMTable table, bool fixTableCellSize)
{
int columnCount = 0;
bool merge = false;
ArrayList rightList = new ArrayList();
int tableLeft = 0;
for(int i = table.ElementList.Count - 1; i >= 0; i--)
{
RTFDOMTableRow row = (RTFDOMTableRow)table.ElementList[i];
if(row.ElementList.Count == 0)
{
table.ElementList.RemoveAt(i);
}
}
foreach(RTFDOMTableRow row in table.ElementList)
{
int lastCellX = 0;
columnCount = Math.Max(columnCount, row.ElementList.Count);
if(row.HasAttribute(RTFConstant.IROW))
{
row.RowIndex = row.AttributeList[RTFConstant.IROW];
}
row.IsLastRow = row.HasAttribute(RTFConstant.LASTROW);
row.Header = row.HasAttribute(RTFConstant.TRHDR);
if(row.HasAttribute(RTFConstant.TRRH))
{
row.Height = row.AttributeList[RTFConstant.TRRH];
if(row.Height == 0)
{
row.Height = this.DefaultRowHeight;
}
else if(row.Height < 0)
{
row.Height = -row.Height;
}
}
else
{
row.Height = this.DefaultRowHeight;
}
if(row.HasAttribute(RTFConstant.TRPADDL))
{
row.PaddingLeft = row.AttributeList[RTFConstant.TRPADDL];
}
else
{
row.PaddingLeft = int.MinValue;
}
if(row.HasAttribute(RTFConstant.TRPADDT))
{
row.PaddingTop = row.AttributeList[RTFConstant.TRPADDT];
}
else
{
row.PaddingTop = int.MinValue;
}
if(row.HasAttribute(RTFConstant.TRPADDR))
{
row.PaddingRight = row.AttributeList[RTFConstant.TRPADDR];
}
else
{
row.PaddingRight = int.MinValue;
}
if(row.HasAttribute(RTFConstant.TRPADDB))
{
row.PaddingBottom = row.AttributeList[RTFConstant.TRPADDB];
}
else
{
row.PaddingBottom = int.MinValue;
}
if(row.HasAttribute(RTFConstant.TRLEFT))
{
tableLeft = row.AttributeList[RTFConstant.TRLEFT];
}
if(row.HasAttribute(RTFConstant.TRCBPAT))
{
row.Format.BackgroundColor = this.ColorTable.GetColor(row.AttributeList[RTFConstant.TRCBPAT], Color.Transparent);
}
int widthCount = 0;
foreach(RTFDOMTableCell cell in row.ElementList)
{
if(cell.HasAttribute(RTFConstant.CLVMGF))
{
merge = true;
}
if(cell.HasAttribute(RTFConstant.CLVMRG))
{
merge = true;
}
if(cell.HasAttribute(RTFConstant.CLPADL))
{
cell.PaddingLeft = cell.AttributeList[RTFConstant.CLPADL];
}
else
{
cell.PaddingLeft = int.MinValue;
}
if(cell.HasAttribute(RTFConstant.CLPADR))
{
cell.PaddingRight = cell.AttributeList[RTFConstant.CLPADR];
}
else
{
cell.PaddingRight = int.MinValue;
}
if(cell.HasAttribute(RTFConstant.CLPADT))
{
cell.PaddingTop = cell.AttributeList[RTFConstant.CLPADT];
}
else
{
cell.PaddingTop = int.MinValue;
}
if(cell.HasAttribute(RTFConstant.CLPADB))
{
cell.PaddingBottom = cell.AttributeList[RTFConstant.CLPADB];
}
else
{
cell.PaddingBottom = int.MinValue;
}
cell.Format.LeftBorder = cell.HasAttribute(RTFConstant.CLBRDRL);
cell.Format.TopBorder = cell.HasAttribute(RTFConstant.CLBRDRT);
cell.Format.RightBorder = cell.HasAttribute(RTFConstant.CLBRDRR);
cell.Format.BottomBorder = cell.HasAttribute(RTFConstant.CLBRDRB);
if(cell.HasAttribute(RTFConstant.BRDRCF))
{
cell.Format.BorderColor = this.ColorTable.GetColor(cell.GetAttributeValue(RTFConstant.BRDRCF, 1), Color.Black);
}
for(int i = cell.AttributeList.Count - 1; i >= 0; i--)
{
string name3 = cell.AttributeList.GetItem(i).Name;
if(name3 == RTFConstant.BRDRTBL || name3 == RTFConstant.BRDRNONE || name3 == RTFConstant.BRDRNIL)
{
for(int j = i - 1; j >= 0; j--)
{
string name2 = cell.AttributeList.GetItem(j).Name;
if(name2 == RTFConstant.CLBRDRL)
{
cell.Format.LeftBorder = false;
break;
}
else if(name2 == RTFConstant.CLBRDRT)
{
cell.Format.TopBorder = false;
break;
}
else if(name2 == RTFConstant.CLBRDRR)
{
cell.Format.RightBorder = false;
break;
}
else if(name2 == RTFConstant.CLBRDRB)
{
cell.Format.BottomBorder = false;
break;
}
}
}
}
if(cell.HasAttribute(RTFConstant.CLVERTALT))
{
cell.VerticalAlignment = RTFVerticalAlignment.Top;
}
else if(cell.HasAttribute(RTFConstant.CLVERTALC))
{
cell.VerticalAlignment = RTFVerticalAlignment.Middle;
}
else if(cell.HasAttribute(RTFConstant.CLVERTALB))
{
cell.VerticalAlignment = RTFVerticalAlignment.Bottom;
}
if(cell.HasAttribute(RTFConstant.CLCBPAT))
{
cell.Format.BackgroundColor = this.ColorTable.GetColor(cell.AttributeList[RTFConstant.CLCBPAT], Color.Transparent);
}
else
{
cell.Format.BackgroundColor = Color.Transparent;
}
if(cell.HasAttribute(RTFConstant.CLCFPAT))
{
cell.Format.BorderColor = this.ColorTable.GetColor(cell.AttributeList[RTFConstant.CLCFPAT], Color.Black);
}
int cellWidth = 2763;
if(cell.HasAttribute(RTFConstant.CELLX))
{
cellWidth = cell.AttributeList[RTFConstant.CELLX] - lastCellX;
if(cellWidth < 100)
{
cellWidth = 100;
}
}
int right = lastCellX + cellWidth;
for(int i = 0; i < rightList.Count; i++)
{
if(Math.Abs(right - (int)rightList[i]) < 45)
{
right = (int)rightList[i];
cellWidth = right - lastCellX;
break;
}
}
cell.Left = lastCellX;
cell.Width = cellWidth;
widthCount += cellWidth;
if(rightList.Contains(right) == false)
{
rightList.Add(right);
}
lastCellX = lastCellX + cellWidth;
}
row.Width = widthCount;
}
if(rightList.Count == 0)
{
int temporaryColumnCount = 1;
foreach(RTFDOMTableRow row in table.ElementList)
{
temporaryColumnCount = Math.Max(temporaryColumnCount, row.ElementList.Count);
}
int width = (int)(ClientAreaWidth / temporaryColumnCount);
for(int iCount = 0; iCount < temporaryColumnCount; iCount++)
{
rightList.Add(iCount * width + width);
}
}
rightList.Add(0);
rightList.Sort();
for(int i = 1; i < rightList.Count; i++)
{
RTFDomTableColumn column = new RTFDomTableColumn();
column.Width = (int)rightList[i] - (int)rightList[i - 1];
table.ColumnList.Add(column);
}
for(int y = 1; y < table.ElementList.Count; y++)
{
RTFDOMTableRow row = (RTFDOMTableRow)table.ElementList[y];
for(int x = 0; x < row.ElementList.Count; x++)
{
RTFDOMTableCell cell = (RTFDOMTableCell)row.ElementList[x];
if(cell.Width == 0)
{
RTFDOMTableRow previousRow = (RTFDOMTableRow)table.ElementList[y - 1];
if(previousRow.ElementList.Count > x)
{
RTFDOMTableCell preCell = (RTFDOMTableCell)previousRow.ElementList[x];
cell.Left = preCell.Left;
cell.Width = preCell.Width;
CopyStyleAttribute(cell, preCell.AttributeList);
}
}
}
}
if(merge == false)
{
foreach(RTFDOMTableRow row in table.ElementList)
{
if(row.ElementList.Count < table.ColumnList.Count)
{
merge = true;
break;
}
}
}
if(merge)
{
foreach(RTFDOMTableRow row in table.ElementList)
{
if(row.ElementList.Count != table.ColumnList.Count)
{
RTFDOMElement[] cellArray = row.ElementList.ToArray();
foreach(RTFDOMTableCell cell in cellArray)
{
int index1 = rightList.IndexOf(cell.Left);
int index2 = rightList.IndexOf(cell.Left + cell.Width);
int columnSpan = index2 - index1;
bool verticalMerge = cell.HasAttribute(RTFConstant.CLVMRG);
if(verticalMerge == false)
{
cell.ColumnSpan = columnSpan;
}
if(row.ElementList.LastElement == cell)
{
cell.ColumnSpan = table.ColumnList.Count - row.ElementList.Count + 1;
columnSpan = cell.ColumnSpan;
}
for(int i = 0; i < columnSpan - 1; i++)
{
RTFDOMTableCell newCell = new RTFDOMTableCell();
newCell.AttributeList = cell.AttributeList.Clone();
row.ElementList.Insert(row.ElementList.GetIndex(cell) + 1, newCell);
if(verticalMerge)
{
newCell.AttributeList[RTFConstant.CLVMRG] = 1;
newCell.OverrideCell = cell;
}
}
}
if(row.ElementList.Count != table.ColumnList.Count)
{
RTFDOMTableCell lastCell = (RTFDOMTableCell)row.ElementList.LastElement;
for(int i = row.ElementList.Count; i < rightList.Count; i++)
{
RTFDOMTableCell newCell = new RTFDOMTableCell();
CopyStyleAttribute(newCell, lastCell.AttributeList);
row.ElementList.Add(newCell);
}
}
}
}
foreach(RTFDOMTableRow row in table.ElementList)
{
foreach(RTFDOMTableCell cell in row.ElementList)
{
if(cell.HasAttribute(RTFConstant.CLVMGF) == false)
{
continue;
}
int x = row.ElementList.GetIndex(cell);
for(int y = table.ElementList.GetIndex(row) + 1; y < table.ElementList.Count; y++)
{
RTFDOMTableRow temporaryRow = (RTFDOMTableRow)table.ElementList[y];
RTFDOMTableCell temporaryCell = (RTFDOMTableCell)temporaryRow.ElementList[x];
if(temporaryCell.HasAttribute(RTFConstant.CLVMRG))
{
if(temporaryCell.OverrideCell != null)
{
break;
}
cell.RowSpan++;
temporaryCell.OverrideCell = cell;
}
else
{
break;
}
}
}
}
foreach(RTFDOMTableRow row in table.ElementList)
{
foreach(RTFDOMTableCell cell in row.ElementList)
{
if(cell.RowSpan > 1 || cell.ColumnSpan > 1)
{
for(int y = 1; y <= cell.RowSpan; y++)
{
for(int x = 1; x <= cell.ColumnSpan; x++)
{
int rowIndex = table.ElementList.GetIndex(row) + y - 1;
int columnIndex = row.ElementList.GetIndex(cell) + x - 1;
RTFDOMTableCell temporaryCell = (RTFDOMTableCell)table.ElementList[rowIndex].ElementList[columnIndex];
if(cell != temporaryCell)
{
temporaryCell.OverrideCell = cell;
}
}
}
}
}
}
}
if(fixTableCellSize)
{
if(table.ColumnList.Count > 0)
{
((RTFDomTableColumn)table.ColumnList[0]).Width -= tableLeft;
}
}
}
#endregion
#region 스타일 특성 복사하기 - CopyStyleAttribute(cell, sourceAttributeList)
/// <summary>
/// 스타일 특성 복사하기
/// </summary>
/// <param name="cell">테이블 셀</param>
/// <param name="sourceAttributeList">소스 특성 리스트</param>
private void CopyStyleAttribute(RTFDOMTableCell cell, RTFAttributeList sourceAttributeList)
{
RTFAttributeList targetAttributeList = sourceAttributeList.Clone();
targetAttributeList.Remove(RTFConstant.CLVMGF);
targetAttributeList.Remove(RTFConstant.CLVMRG);
cell.AttributeList = targetAttributeList;
}
#endregion
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"RTFDocument:{this.documentInfo.Title}";
}
#endregion
#region 텍스트 적용하기 - ApplyText(textContainer, reader, format)
/// <summary>
/// 텍스트 적용하기
/// </summary>
/// <param name="textContainer">텍스트 컨테이너</param>
/// <param name="reader">리더</param>
/// <param name="format">문서 포맷 정보</param>
/// <returns>처리 결과</returns>
private bool ApplyText(RTFTextContainer textContainer, RTFReader reader, RTFDocumentFormatInfo format)
{
if(textContainer.HasContent)
{
string textContainerText = textContainer.Text;
textContainer.Clear();
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null && image.Locked == false)
{
image.Data = GetByteArray(textContainerText);
image.Format = format.Clone();
image.Width = (int)(image.DesiredWidth * image.ScaleX / 100);
image.Height = (int)(image.DesiredHeight * image.ScaleY / 100);
image.Locked = true;
if(reader.CurrentTokenType != RTFTokenType.GroupEnd)
{
ReadToEndGround(reader);
}
return true;
}
else if(format.ReadText && this.startContent)
{
RTFDOMText text = new RTFDOMText();
text.NativeLevel = textContainer.Level;
text.Format = format.Clone();
if(text.Format.TextAlignment == RTFTextAlignment.JUSTIFY)
{
text.Format.TextAlignment = RTFTextAlignment.LEFT;
}
text.Text = textContainerText;
AddContentElement(text);
}
}
return false;
}
#endregion
#region 로드하기 - Load(reader , parentFormat)
/// <summary>
/// 로드하기
/// </summary>
/// <param name="reader">리더</param>
/// <param name="parentFormat">부모 문서 포맷 정보</param>
private void Load(RTFReader reader , RTFDocumentFormatInfo parentFormat)
{
bool forbitPard = false;
RTFDocumentFormatInfo format = null;
if(this.paragraphFormat == null)
{
this.paragraphFormat = new RTFDocumentFormatInfo();
}
if(parentFormat == null)
{
format = new RTFDocumentFormatInfo();
}
else
{
format = parentFormat.Clone();
format.NativeLevel = parentFormat.NativeLevel + 1;
}
RTFTextContainer textContainer = new RTFTextContainer(this);
int levelBack = reader.Level;
while(reader.ReadToken() != null)
{
if(reader.TokenCount - this.tokenCount > 100)
{
this.tokenCount = reader.TokenCount;
FireProgressEvent(reader.ContentLength, reader.ContentPosition, null);
}
if(this.startContent)
{
if(textContainer.Accept(reader.CurrentToken, reader))
{
textContainer.Level = reader.Level;
continue;
}
else if(textContainer.HasContent)
{
if(ApplyText(textContainer, reader, format))
{
break;
}
}
}
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
RTFDOMElement[] elementArray = GetLastElementArray(true);
for(int i = 0 ; i < elementArray.Length ; i ++)
{
RTFDOMElement element = elementArray[i];
if(element.NativeLevel >= 0 && element.NativeLevel > reader.Level)
{
for(int j = i ; j < elementArray.Length; j++)
{
elementArray[j].Locked = true;
}
break;
}
}
break;
}
if(reader.Level < levelBack)
{
break;
}
if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
Load(reader, format);
if(reader.Level < levelBack)
{
break;
}
}
if
(
reader.CurrentTokenType == RTFTokenType.Control ||
reader.CurrentTokenType == RTFTokenType.Keyword ||
reader.CurrentTokenType == RTFTokenType.ExtendedKeyword
)
{
switch(reader.CurrentKeyword)
{
case "fromhtml" :
ReadHTMLContent(reader);
return;
case RTFConstant.LISTTABLE :
ReadListTable(reader);
return;
case RTFConstant.LISTOVERRIDE :
ReadToEndGround(reader);
break;
case RTFConstant.ANSI :
break;
case RTFConstant.ANSICPG :
this.defaultEncoding = Encoding.GetEncoding(reader.CurrentParameter);
break;
case RTFConstant.FONTTBL :
ReadFontTable(reader);
break;
case "listoverridetable" :
ReadListOverrideTable(reader);
break;
case "filetbl" :
ReadToEndGround(reader);
break;
case RTFConstant.COLORTBL :
ReadColorTable(reader);
return;
case "stylesheet" :
ReadToEndGround(reader);
break;
case RTFConstant.GENERATOR :
Generator = ReadInnerText(reader, true);
break;
case RTFConstant.INFO :
ReadDocumentInfo(reader);
return ;
case RTFConstant.HEADERY :
if(reader.HasCurrentParameter)
{
HeaderDistance = reader.CurrentParameter;
}
break;
case RTFConstant.FOOTERY :
if(reader.HasCurrentParameter)
{
FooterDistance = reader.CurrentParameter;
}
break;
case RTFConstant.HEADER :
{
RTFDOMHeader header = new RTFDOMHeader();
header.Style = HeaderFooterStyle.ALL_PAGES;
AppendChild(header);
Load(reader, parentFormat);
header.Locked = true;
this.paragraphFormat = new RTFDocumentFormatInfo();
break;
}
case RTFConstant.HEADERL :
{
RTFDOMHeader header = new RTFDOMHeader();
header.Style = HeaderFooterStyle.LEFT_PAGES;
AppendChild(header);
Load(reader, parentFormat);
header.Locked = true;
this.paragraphFormat = new RTFDocumentFormatInfo();
break;
}
case RTFConstant.HEADERR :
{
RTFDOMHeader header = new RTFDOMHeader();
header.Style = HeaderFooterStyle.RIGHT_PAGES;
AppendChild(header);
Load(reader, parentFormat);
header.Locked = true;
this.paragraphFormat = new RTFDocumentFormatInfo();
break;
}
case RTFConstant.HEADERF :
{
RTFDOMHeader header = new RTFDOMHeader();
header.Style = HeaderFooterStyle.FIRST_PAGE;
AppendChild(header);
Load(reader, parentFormat);
header.Locked = true;
this.paragraphFormat = new RTFDocumentFormatInfo();
break;
}
case RTFConstant.FOOTER :
{
RTFDOMFooter footer = new RTFDOMFooter();
footer.Style = HeaderFooterStyle.ALL_PAGES;
AppendChild(footer);
Load(reader, parentFormat);
footer.Locked = true;
this.paragraphFormat = new RTFDocumentFormatInfo();
break;
}
case RTFConstant.FOOTERL :
{
RTFDOMFooter footer = new RTFDOMFooter();
footer.Style = HeaderFooterStyle.LEFT_PAGES ;
AppendChild(footer);
Load(reader, parentFormat);
footer.Locked = true;
this.paragraphFormat = new RTFDocumentFormatInfo();
break;
}
case RTFConstant.FOOTERR :
{
RTFDOMFooter footer = new RTFDOMFooter();
footer.Style = HeaderFooterStyle.RIGHT_PAGES ;
AppendChild(footer);
Load(reader, parentFormat);
footer.Locked = true;
this.paragraphFormat = new RTFDocumentFormatInfo();
break;
}
case RTFConstant.FOOTERF :
{
RTFDOMFooter footer = new RTFDOMFooter();
footer.Style = HeaderFooterStyle.FIRST_PAGE ;
AppendChild(footer);
Load(reader, parentFormat);
footer.Locked = true;
this.paragraphFormat = new RTFDocumentFormatInfo();
break;
}
case RTFConstant.XMLNS :
ReadToEndGround(reader);
break;
case RTFConstant.NONESTTABLES :
ReadToEndGround(reader);
break;
case RTFConstant.XMLOPEN :
break;
case RTFConstant.REVTBL :
break;
case RTFConstant.PAPERW :
this.paperWidth = reader.CurrentParameter;
break;
case RTFConstant.PAPERH :
this.paperHeight = reader.CurrentParameter;
break;
case RTFConstant.MARGL :
this.leftMargin = reader.CurrentParameter;
break;
case RTFConstant.MARGR :
this.rightMargin = reader.CurrentParameter;
break;
case RTFConstant.MARGB :
this.bottomMargin = reader.CurrentParameter;
break;
case RTFConstant.MARGT :
this.topMargin = reader.CurrentParameter;
break;
case RTFConstant.LANDSCAPE :
this.landscape = true;
break;
case RTFConstant.FCHARS :
FollowingCharacters = ReadInnerText(reader, true);
break;
case RTFConstant.LCHARS :
LeadingCharacters = ReadInnerText(reader, true);
break;
case "pnseclvl" :
ReadToEndGround(reader);
break;
case RTFConstant.PARD :
this.startContent = true;
if(forbitPard)
{
continue;
}
this.paragraphFormat.ResetParagraph();
break;
case RTFConstant.PAR :
{
this.startContent = true;
if(GetLastElement(typeof(RTFDOMParagraph)) == null)
{
RTFDOMParagraph paragraph = new RTFDOMParagraph();
paragraph.Format = this.paragraphFormat ;
this.paragraphFormat = this.paragraphFormat.Clone();
AddContentElement(paragraph);
paragraph.Locked = true;
}
else
{
CompleteParagraph();
RTFDOMParagraph paragraph = new RTFDOMParagraph();
paragraph.Format = this.paragraphFormat;
AddContentElement(paragraph);
}
this.startContent = true;
break;
}
case RTFConstant.PAGE :
this.startContent = true;
CompleteParagraph();
AddContentElement(new RTFDOMPageBreak());
break;
case RTFConstant.PAGEBB :
this.startContent = true;
this.paragraphFormat.PageBreak = true;
break;
case RTFConstant.QL :
this.startContent = true;
this.paragraphFormat.TextAlignment = RTFTextAlignment.LEFT;
break;
case RTFConstant.QC :
this.startContent = true;
this.paragraphFormat.TextAlignment = RTFTextAlignment.CENTER;
break;
case RTFConstant.QR :
this.startContent = true;
this.paragraphFormat.TextAlignment = RTFTextAlignment.RIGHT;
break;
case RTFConstant.QJ:
this.startContent = true;
this.paragraphFormat.TextAlignment = RTFTextAlignment.JUSTIFY;
break;
case RTFConstant.SL :
this.startContent = true;
if(reader.CurrentParameter >= 0)
{
this.paragraphFormat.LineSpacing = reader.CurrentParameter;
}
break;
case RTFConstant.SLMULT :
this.startContent = true;
this.paragraphFormat.MultiLineSpacing = (reader.CurrentParameter == 1);
break;
case RTFConstant.SB :
this.startContent = true;
this.paragraphFormat.SpacingBeforeParagraph = reader.CurrentParameter;
break;
case RTFConstant.SA :
this.startContent = true;
this.paragraphFormat.SpacingAfterParagraph = reader.CurrentParameter;
break;
case RTFConstant.FI :
this.startContent = true;
this.paragraphFormat.ParagraphFirstLineIndent = reader.CurrentParameter;
break;
case RTFConstant.BRDRW:
this.startContent = true;
if(reader.HasCurrentParameter)
{
this.paragraphFormat.BorderWidth = reader.CurrentParameter;
}
break;
case RTFConstant.PN :
this.startContent = true;
this.paragraphFormat.ListID = -1;
break;
case RTFConstant.PNTEXT :
break;
case RTFConstant.PNTXTB :
break;
case RTFConstant.PNTXTA :
break;
case RTFConstant.PNLVLBODY :
this.startContent = true;
break;
case RTFConstant.PNLVLBLT :
this.startContent = true;
break;
case RTFConstant.LISTTEXT :
this.startContent = true;
break;
case RTFConstant.LS :
this.startContent = true;
this.paragraphFormat.ListID = reader.CurrentParameter;
break;
case RTFConstant.LI :
this.startContent = true;
if(reader.HasCurrentParameter)
{
this.paragraphFormat.LeftIndent = reader.CurrentParameter;
}
break;
case RTFConstant.LINE :
{
this.startContent = true;
if(format.ReadText)
{
RTFDOMLineBreak lineBreak = new RTFDOMLineBreak();
lineBreak.NativeLevel = reader.Level;
AddContentElement(lineBreak);
}
break;
}
case RTFConstant.INSRSID :
break;
case RTFConstant.PLAIN :
this.startContent = true;
format.ResetText();
break;
case RTFConstant.F :
{
this.startContent = true;
if(format.ReadText)
{
string fontName = FontTable.GetFontName(reader.CurrentParameter);
if(fontName != null)
{
fontName = fontName.Trim();
}
if(fontName == null || fontName.Length == 0)
{
fontName = _defaultFontName;
}
if(ChangeTimesNewRoman)
{
if(fontName == "Times New Roman")
{
fontName = _defaultFontName;
}
}
format.FontName = fontName;
}
this.fontChartSetEncoding = FontTable[reader.CurrentParameter].Encoding;
break;
}
case RTFConstant.AF :
this.associateFontChartSetEncoding = FontTable[reader.CurrentParameter].Encoding;
break;
case RTFConstant.FS :
this.startContent = true;
if(format.ReadText)
{
if(reader.HasCurrentParameter)
{
format.FontSize = reader.CurrentParameter / 2.0f;
}
}
break;
case RTFConstant.CF :
this.startContent = true;
if(format.ReadText)
{
if(reader.HasCurrentParameter)
{
format.TextColor = ColorTable.GetColor(reader.CurrentParameter, Color.Black);
}
}
break;
case RTFConstant.CB :
case RTFConstant.CHCBPAT :
this.startContent = true;
if(format.ReadText)
{
if(reader.HasCurrentParameter)
{
format.BackgroundColor = ColorTable.GetColor(reader.CurrentParameter, Color.Empty);
}
}
break;
case RTFConstant.B :
this.startContent = true;
if(format.ReadText)
{
format.Bold = (reader.HasCurrentParameter == false || reader.CurrentParameter != 0);
}
break;
case RTFConstant.V :
this.startContent = true;
if(format.ReadText)
{
if(reader.HasCurrentParameter && reader.CurrentParameter == 0)
{
format.Hidden = false;
}
else
{
format.Hidden = true;
}
}
break;
case RTFConstant.HIGHLIGHT :
this.startContent = true;
if(format.ReadText)
{
if(reader.HasCurrentParameter)
{
format.BackgroundColor = ColorTable.GetColor(reader.CurrentParameter , Color.Empty);
}
}
break;
case RTFConstant.I :
this.startContent = true;
if(format.ReadText)
{
format.Italic = (reader.HasCurrentParameter == false || reader.CurrentParameter != 0);
}
break;
case RTFConstant.UL :
this.startContent = true;
if(format.ReadText)
{
format.Underline = (reader.HasCurrentParameter == false || reader.CurrentParameter != 0);
}
break;
case RTFConstant.NOUL :
this.startContent = true;
format.Underline = false;
break;
case RTFConstant.STRIKE :
this.startContent = true;
if(format.ReadText)
{
format.Strikeout = (reader.HasCurrentParameter == false || reader.CurrentParameter != 0);
}
break;
case RTFConstant.SUB :
this.startContent = true;
if(format.ReadText)
{
format.Subscript = (reader.HasCurrentParameter == false || reader.CurrentParameter != 0);
}
break;
case RTFConstant.SUPER :
this.startContent = true;
if(format.ReadText)
{
format.Superscript = (reader.HasCurrentParameter == false || reader.CurrentParameter != 0);
}
break;
case RTFConstant.NOSUPERSUB :
this.startContent = true;
format.Subscript = false;
format.Superscript = false;
break;
case RTFConstant.BRDRB :
this.startContent = true;
this.paragraphFormat.BottomBorder = true;
break;
case RTFConstant.BRDRL :
this.startContent = true;
this.paragraphFormat.LeftBorder = true;
break;
case RTFConstant.BRDRR :
this.startContent = true;
this.paragraphFormat.RightBorder = true;
break;
case RTFConstant.BRDRT :
this.startContent = true;
this.paragraphFormat.BottomBorder = true;
break;
case RTFConstant.BRDRCF :
{
this.startContent = true;
RTFDOMElement element = this.GetLastElement(typeof(RTFDOMTableRow) , false);
if(element is RTFDOMTableRow)
{
RTFDOMTableRow row = (RTFDOMTableRow)element;
RTFAttributeList attributeList = null;
if(row.CellSettingList.Count > 0)
{
attributeList = (RTFAttributeList)row.CellSettingList[row.CellSettingList.Count - 1];
attributeList.Add(reader.CurrentKeyword, reader.CurrentParameter);
}
}
else
{
this.paragraphFormat.BorderColor = ColorTable.GetColor(reader.CurrentParameter , Color.Black);
format.BorderColor = format.BorderColor;
}
break;
}
case RTFConstant.BRDRS :
this.startContent = true;
this.paragraphFormat.BorderThickness = false;
format.BorderThickness = false;
break;
case RTFConstant.BRDRTH :
this.startContent = true;
this.paragraphFormat.BorderThickness = true;
format.BorderThickness = true;
break;
case RTFConstant.BRDRDOT :
this.startContent = true;
this.paragraphFormat.BorderStyle= DashStyle.Dot;
format.BorderStyle = DashStyle.Dot;
break;
case RTFConstant.BRDRDASH :
this.startContent = true;
this.paragraphFormat.BorderStyle = DashStyle.Dash;
format.BorderStyle = DashStyle.Dash;
break;
case RTFConstant.BRDRDASHD :
this.startContent = true;
this.paragraphFormat.BorderStyle = DashStyle.DashDot;
format.BorderStyle = DashStyle.DashDot;
break;
case RTFConstant.BRDRDASHDD :
this.startContent = true;
this.paragraphFormat.BorderStyle = DashStyle.DashDotDot;
format.BorderStyle = DashStyle.DashDotDot;
break;
case RTFConstant.BRDRNIL :
this.startContent = true;
this.paragraphFormat.LeftBorder = false;
this.paragraphFormat.TopBorder = false;
this.paragraphFormat.RightBorder = false;
this.paragraphFormat.BottomBorder = false;
format.LeftBorder = false;
format.TopBorder = false;
format.RightBorder = false;
format.BottomBorder = false;
break;
case RTFConstant.BRSP :
this.startContent = true;
if(reader.HasCurrentParameter)
{
this.paragraphFormat.BorderSpacing = reader.CurrentParameter;
}
break;
case RTFConstant.CHBRDR :
this.startContent = true;
format.LeftBorder = true;
format.TopBorder = true;
format.RightBorder = true;
format.BottomBorder = true;
break;
case RTFConstant.BKMKSTART :
{
this.startContent = true;
if(format.ReadText && this.startContent)
{
RTFDOMBookmark bookmark = new RTFDOMBookmark();
bookmark.Name = ReadInnerText(reader, true);
bookmark.Locked = true;
AddContentElement(bookmark);
}
break;
}
case RTFConstant.BKMKEND :
forbitPard = true;
format.ReadText = false;
break;
case RTFConstant.FIELD :
this.startContent = true;
ReadDOMField(reader, format);
return;
case RTFConstant.OBJECT :
this.startContent = true;
ReadDOMObject(reader, format);
return;
case RTFConstant.SHPPICT :
break;
case RTFConstant.NONSHPPICT :
ReadToEndGround(reader);
break;
case RTFConstant.PICT :
{
this.startContent = true;
RTFDOMImage image = new RTFDOMImage();
image.NativeLevel = reader.Level;
AddContentElement(image);
break;
}
case RTFConstant.PICSCALEX :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.ScaleX = reader.CurrentParameter;
}
break;
}
case RTFConstant.PICSCALEY :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.ScaleY = reader.CurrentParameter;
}
break;
}
case RTFConstant.PICWGOAL :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.DesiredWidth = reader.CurrentParameter;
}
break;
}
case RTFConstant.PICHGOAL :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.DesiredHeight = reader.CurrentParameter;
}
break;
}
case RTFConstant.BLIPUID :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.ID = ReadInnerText(reader, true);
}
break;
}
case RTFConstant.EMFBLIP :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.PictureType = RTFPictureType.EMF;
}
break;
}
case RTFConstant.PNGBLIP :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.PictureType = RTFPictureType.PNG;
}
break;
}
case RTFConstant.JPEGBLIP :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.PictureType = RTFPictureType.JPEG;
}
break;
}
case RTFConstant.MACPICT :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.PictureType = RTFPictureType.PICT;
}
break;
}
case RTFConstant.PMMETAFILE :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.PictureType = RTFPictureType.OS2METAFILE;
}
break;
}
case RTFConstant.WMETAFILE :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.PictureType = RTFPictureType.METAFILE;
}
break;
}
case RTFConstant.DIBITMAP :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.PictureType = RTFPictureType.DIB;
}
break;
}
case RTFConstant.WBITMAP :
{
RTFDOMImage image = (RTFDOMImage)GetLastElement(typeof(RTFDOMImage));
if(image != null)
{
image.PictureType = RTFPictureType.BITMAP;
}
break;
}
case RTFConstant.SP :
{
int level = 0;
string name = null;
string value = null;
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
level++;
}
else if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
level--;
if(level < 0)
{
break;
}
}
else if(reader.CurrentKeyword == RTFConstant.SN)
{
name = ReadInnerText(reader, true);
}
else if(reader.CurrentKeyword == RTFConstant.SV)
{
value = ReadInnerText(reader, true);
}
}
RTFDOMShape shape = (RTFDOMShape)GetLastElement(typeof(RTFDOMShape));
if(shape != null)
{
shape.AttrbuteCollection[name] = value;
}
else
{
RTFDOMShapeGroup shapeGroup = (RTFDOMShapeGroup)GetLastElement(typeof(RTFDOMShapeGroup));
if(shapeGroup != null)
{
shapeGroup.AttrbuteCollection[name] = value;
}
}
break;
}
case RTFConstant.SHPTXT :
break;
case RTFConstant.SHPRSLT :
ReadToEndGround(reader);
break ;
case RTFConstant.SHP :
{
this.startContent = true;
RTFDOMShape shape = new RTFDOMShape();
shape.NativeLevel = reader.Level;
AddContentElement(shape);
break;
}
case RTFConstant.SHPLEFT :
{
RTFDOMShape shape = (RTFDOMShape)GetLastElement(typeof(RTFDOMShape));
if(shape != null)
{
shape.Left = reader.CurrentParameter;
}
break;
}
case RTFConstant.SHPTOP :
{
RTFDOMShape shape = (RTFDOMShape)GetLastElement(typeof(RTFDOMShape));
if(shape != null)
{
shape.Top = reader.CurrentParameter;
}
break;
}
case RTFConstant.SHPRIGHT :
{
RTFDOMShape shape = (RTFDOMShape)GetLastElement(typeof(RTFDOMShape));
if(shape != null)
{
shape.Width = reader.CurrentParameter - shape.Left;
}
break;
}
case RTFConstant.SHPBOTTOM :
{
RTFDOMShape shape = (RTFDOMShape)GetLastElement(typeof(RTFDOMShape));
if(shape != null)
{
shape.Height = reader.CurrentParameter - shape.Top;
}
break;
}
case RTFConstant.SHPLID :
{
RTFDOMShape shape = (RTFDOMShape)GetLastElement(typeof(RTFDOMShape));
if(shape != null)
{
shape.ShapeID = reader.CurrentParameter;
}
break;
}
case RTFConstant.SHPZ :
{
RTFDOMShape shape = (RTFDOMShape)GetLastElement(typeof(RTFDOMShape));
if(shape != null)
{
shape.ZIndex = reader.CurrentParameter;
}
break;
}
case RTFConstant.SHPGRP :
{
RTFDOMShapeGroup shapeGroup = new RTFDOMShapeGroup();
shapeGroup.NativeLevel = reader.Level;
AddContentElement(shapeGroup);
break;
}
case RTFConstant.SHPINST :
break;
case RTFConstant.INTBL :
case RTFConstant.TROWD :
case RTFConstant.ITAP :
{
this.startContent = true;
RTFDOMElement[] lastElementArray = GetLastElementArray(true);
RTFDOMElement lastUnlockElement = null;
RTFDOMElement lastTableElement = null;
for(int i = lastElementArray.Length - 1; i >= 0; i--)
{
RTFDOMElement element = lastElementArray[i];
if(element.Locked == false)
{
if(lastUnlockElement == null && !(element is RTFDOMParagraph))
{
lastUnlockElement = element;
}
if(element is RTFDOMTableRow || element is RTFDOMTableCell)
{
lastTableElement = element;
break;
}
}
}
if(reader.CurrentKeyword == RTFConstant.INTBL)
{
if(lastTableElement == null)
{
RTFDOMTableRow row = new RTFDOMTableRow();
row.NativeLevel = reader.Level;
lastUnlockElement.AppendChild(row);
}
}
else if(reader.CurrentKeyword == RTFConstant.TROWD)
{
RTFDOMTableRow row = null;
if(lastTableElement == null)
{
row = new RTFDOMTableRow();
row.NativeLevel = reader.Level;
lastUnlockElement.AppendChild(row);
}
else
{
row = lastTableElement as RTFDOMTableRow;
if(row == null)
{
row = (RTFDOMTableRow)lastTableElement.ParentElement;
}
}
row.AttributeList.Clear();
row.CellSettingList.Clear();
this.paragraphFormat.ResetParagraph();
}
else if(reader.CurrentKeyword == RTFConstant.ITAP)
{
RTFDOMTableRow row = null;
if(reader.CurrentParameter == 0)
{
}
else
{
if(lastTableElement == null)
{
row = new RTFDOMTableRow();
row.NativeLevel = reader.Level;
lastUnlockElement.AppendChild(row);
}
else
{
row = lastTableElement as RTFDOMTableRow;
if(row == null)
{
row = (RTFDOMTableRow)lastTableElement.ParentElement;
}
}
if(reader.CurrentParameter == row.Level)
{
}
else if(reader.CurrentParameter > row.Level)
{
RTFDOMTableRow newRow = new RTFDOMTableRow();
newRow.Level = reader.CurrentParameter;
RTFDOMTableCell parentCell = (RTFDOMTableCell)GetLastElement(typeof(RTFDOMTableCell), false);
if(parentCell == null)
{
AddContentElement(newRow);
}
else
{
parentCell.AppendChild(newRow);
}
}
else if(reader.CurrentParameter < row.Level)
{
}
}
}
break;
}
case RTFConstant.NESTTABLEPROPS :
break;
case RTFConstant.ROW :
{
this.startContent = true;
RTFDOMElement[] lastElementArray = GetLastElementArray(true);
for(int i = lastElementArray.Length - 1; i >= 0; i--)
{
lastElementArray[i].Locked = true;
if(lastElementArray[i] is RTFDOMTableRow)
{
break;
}
}
break;
}
case RTFConstant.NESTROW :
{
this.startContent = true;
RTFDOMElement[] elementArray = GetLastElementArray(true);
for(int i = elementArray.Length - 1; i >= 0; i--)
{
elementArray[i].Locked = true;
if(elementArray[i] is RTFDOMTableRow)
{
break;
}
}
break;
}
case RTFConstant.TRRH :
case RTFConstant.TRAUTOFIT :
case RTFConstant.IROWBAND :
case RTFConstant.TRHDR :
case RTFConstant.TRKEEP :
case RTFConstant.TRKEEPFOLLOW :
case RTFConstant.TRLEFT :
case RTFConstant.TRQC :
case RTFConstant.TRQL :
case RTFConstant.TRQR :
case RTFConstant.TRCBPAT :
case RTFConstant.TRCFPAT :
case RTFConstant.TRPAT :
case RTFConstant.TRSHDNG :
case RTFConstant.TRWWIDTH :
case RTFConstant.TRWWIDTHA :
case RTFConstant.IROW :
case RTFConstant.TRPADDB :
case RTFConstant.TRPADDL :
case RTFConstant.TRPADDR :
case RTFConstant.TRPADDT :
case RTFConstant.TRPADDFB :
case RTFConstant.TRPADDFL :
case RTFConstant.TRPADDFR :
case RTFConstant.TRPADDFT :
case RTFConstant.LASTROW :
{
this.startContent = true;
RTFDOMTableRow row = (RTFDOMTableRow)GetLastElement(typeof(RTFDOMTableRow), false);
if(row != null)
{
row.AttributeList.Add(reader.CurrentKeyword , reader.CurrentParameter);
}
break;
}
case RTFConstant.CLVMGF :
case RTFConstant.CLVMRG :
case RTFConstant.CELLX :
case RTFConstant.CLVERTALT :
case RTFConstant.CLVERTALC :
case RTFConstant.CLVERTALB :
case RTFConstant.CLNOWRAP :
case RTFConstant.CLCBPAT :
case RTFConstant.CLCFPAT :
case RTFConstant.CLPADL :
case RTFConstant.CLPADT :
case RTFConstant.CLPADR :
case RTFConstant.CLPADB :
case RTFConstant.CLBRDRL :
case RTFConstant.CLBRDRT :
case RTFConstant.CLBRDRR :
case RTFConstant.CLBRDRB :
case RTFConstant.BRDRTBL :
case RTFConstant.BRDRNONE :
{
this.startContent = true;
RTFDOMTableRow row = (RTFDOMTableRow)GetLastElement(typeof(RTFDOMTableRow), false);
RTFAttributeList attributeList = null;
if(row.CellSettingList.Count > 0)
{
attributeList = (RTFAttributeList)row.CellSettingList[row.CellSettingList.Count - 1];
if(attributeList.Contains(RTFConstant.CELLX))
{
attributeList = new RTFAttributeList();
row.CellSettingList.Add(attributeList);
}
}
if(attributeList == null)
{
attributeList = new RTFAttributeList();
row.CellSettingList.Add(attributeList);
}
attributeList.Add(reader.CurrentKeyword, reader.CurrentParameter);
break;
}
case RTFConstant.CELL :
{
this.startContent = true;
AddContentElement(null);
CompleteParagraph();
this.paragraphFormat.Reset();
format.Reset();
RTFDOMElement[] lastElementArray = GetLastElementArray(true);
for(int i = lastElementArray.Length - 1; i >= 0; i--)
{
if(lastElementArray[i].Locked == false)
{
lastElementArray[i].Locked = true;
if(lastElementArray[i] is RTFDOMTableCell)
{
break;
}
}
}
break;
}
case RTFConstant.NESTCELL :
{
this.startContent = true;
AddContentElement(null);
CompleteParagraph();
RTFDOMElement[] lastElementArray = GetLastElementArray(false);
for(int i = lastElementArray.Length - 1; i >= 0; i--)
{
lastElementArray[i].Locked = true;
if(lastElementArray[i] is RTFDOMTableCell)
{
((RTFDOMTableCell)lastElementArray[i]).Format = format;
break;
}
}
break;
}
default :
if(reader.CurrentTokenType == RTFTokenType.ExtendedKeyword && reader.FirstTokenInGroup)
{
ReadToEndGround(reader);
break ;
}
break;
}
}
}
if(textContainer.HasContent)
{
ApplyText(textContainer, reader, format);
}
}
#endregion
#region 끝까지 읽기 - ReadToEndGround(reader)
/// <summary>
/// 끝까지 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
private void ReadToEndGround(RTFReader reader)
{
reader.ReadToEndGround();
}
#endregion
#region 리스트 오버라이드 테이블 읽기 - ReadListOverrideTable(reader)
/// <summary>
/// 리스트 오버라이드 테이블 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
private void ReadListOverrideTable(RTFReader reader)
{
this.listOverrideTable = new RTFListOverrideTable();
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
break;
}
else if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
int level = reader.Level;
RTFListOverride listOverride = null;
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
break;
}
if(reader.CurrentToken.Keyword == "listoverride")
{
listOverride = new RTFListOverride();
this.listOverrideTable.Add(listOverride);
continue;
}
if(listOverride == null)
{
continue;
}
switch(reader.CurrentToken.Keyword)
{
case "listid" :
listOverride.ListID = reader.CurrentToken.Parameter;
break;
case "listoverridecount" :
listOverride.ListOverriedCount = reader.CurrentToken.Parameter;
break;
case "ls" :
listOverride.ID = reader.CurrentToken.Parameter;
break;
}
}
}
}
}
#endregion
#region HTML 컨텐트 읽기 - ReadHTMLContent(reader)
/// <summary>
/// HTML 컨텐트 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
private void ReadHTMLContent(RTFReader reader)
{
StringBuilder stringBuilder = new StringBuilder();
bool htmlState = true;
while(reader.ReadToken() != null)
{
if(reader.CurrentKeyword == "htmlrtf")
{
if(reader.HasCurrentParameter && reader.CurrentParameter == 0)
{
htmlState = false;
}
else
{
htmlState = true;
}
}
else if(reader.CurrentKeyword == "htmltag")
{
if(reader.InnerReader.Peek() == (int)' ')
{
reader.InnerReader.Read();
}
string text = ReadInnerText(reader, null, true, false, true);
if(string.IsNullOrEmpty(text) == false)
{
stringBuilder.Append(text);
}
}
else if(reader.CurrentTokenType == RTFTokenType.Keyword || reader.CurrentTokenType == RTFTokenType.ExtendedKeyword)
{
if(htmlState == false)
{
switch(reader.CurrentKeyword)
{
case "par" : stringBuilder.Append(Environment.NewLine); break;
case "line" : stringBuilder.Append(Environment.NewLine); break;
case "tab" : stringBuilder.Append("\t"); break;
case "lquote" : stringBuilder.Append("‘"); break;
case "rquote" : stringBuilder.Append("’"); break;
case "ldblquote" : stringBuilder.Append("“"); break;
case "rdblquote" : stringBuilder.Append("”"); break;
case "bullet" : stringBuilder.Append("•" ); break;
case "endash" : stringBuilder.Append("–"); break;
case "emdash" : stringBuilder.Append("—"); break;
case "~" : stringBuilder.Append(" " ); break;
case "_" : stringBuilder.Append("­" ); break;
}
}
}
else if(reader.CurrentTokenType == RTFTokenType.Text)
{
if(htmlState == false)
{
stringBuilder.Append(reader.CurrentKeyword);
}
}
}
HTMLContent = stringBuilder.ToString();
}
#endregion
#region 리스트 테이블 읽기 - ReadListTable(reader)
/// <summary>
/// 리스트 테이블 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
private void ReadListTable(RTFReader reader)
{
this.listTable = new RTFListTable();
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
break;
}
else if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
bool firstRead = true;
RTFList currentList = null;
int level = reader.Level;
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
if(reader.Level < level)
{
break;
}
}
else if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
}
if(firstRead)
{
if(reader.CurrentToken.Keyword != "list")
{
ReadToEndGround(reader);
reader.ReadToken();
break;
}
currentList = new RTFList();
this.listTable.Add(currentList);
firstRead = false;
}
switch(reader.CurrentToken.Keyword)
{
case "listtemplateid" :
currentList.ListTemplateID = reader.CurrentToken.Parameter;
break;
case "listid" :
currentList.ListID = reader.CurrentToken.Parameter;
break;
case "listhybrid" :
currentList.ListHybrid = true;
break;
case "levelfollow" :
currentList.LevelFollow = reader.CurrentToken.Parameter;
break;
case "levelstartat" :
currentList.LevelStartAt = reader.CurrentToken.Parameter;
break;
case "levelnfc" :
if(currentList.NFCLevelNumberType == LevelNumberType.NONE)
{
currentList.NFCLevelNumberType = (LevelNumberType)reader.CurrentToken.Parameter;
}
break;
case "levelnfcn" :
if(currentList.NFCLevelNumberType == LevelNumberType.NONE)
{
currentList.NFCLevelNumberType = (LevelNumberType)reader.CurrentToken.Parameter;
}
break;
case "leveljc" :
currentList.JCLevel = reader.CurrentToken.Parameter;
break;
case "leveltext" :
if(string.IsNullOrEmpty(currentList.LevelText))
{
string text = ReadInnerText(reader, true);
if(text != null && text.Length > 2)
{
int length = (int)text[0];
length = Math.Min(length, text.Length - 1);
text = text.Substring(1, length);
}
currentList.LevelText = text ;
}
break;
case "f" :
currentList.FontName = this.FontTable.GetFontName(reader.CurrentToken.Parameter);
break;
}
}
}
}
}
#endregion
#region 폰트 테이블 읽기 - ReadFontTable(reader)
/// <summary>
/// 폰트 테이블 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
private void ReadFontTable(RTFReader reader)
{
this.fontTable.Clear();
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
break;
}
else if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
int index = -1;
string name = null;
int characterSet = 1;
bool isNull = false;
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
break;
}
else if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
reader.ReadToken();
ReadToEndGround(reader);
reader.ReadToken();
}
else if(reader.CurrentKeyword == "f" && reader.HasCurrentParameter)
{
index = reader.CurrentParameter;
}
else if(reader.CurrentKeyword == "fnil")
{
name = Control.DefaultFont.Name;
isNull = true;
}
else if(reader.CurrentKeyword == RTFConstant.FCHARSET)
{
characterSet = reader.CurrentParameter;
}
else if(reader.CurrentToken.IsTextToken)
{
name = ReadInnerText(reader, reader.CurrentToken, false, false , false);
if(name != null)
{
name = name.Trim();
if(name.EndsWith(";"))
{
name = name.Substring(0, name.Length - 1);
}
}
}
}
if(index >= 0 && name != null)
{
if(name.EndsWith(";"))
{
name = name.Substring(0, name.Length - 1);
}
name = name.Trim();
if(string.IsNullOrEmpty(name))
{
name = Control.DefaultFont.Name;
}
RTFFont font = new RTFFont(index, name);
font.CharacterSet = characterSet;
font.IsNull = isNull;
this.fontTable.Add(font);
}
}
}
}
#endregion
#region 색상 테이블 읽기 - ReadColorTable(reader)
/// <summary>
/// 색상 테이블 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
private void ReadColorTable(RTFReader reader)
{
this.colorTable.Clear();
this.colorTable.CheckValueExistWhenAdd = false;
int red = -1;
int green = -1;
int blue = -1;
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
break;
}
switch(reader.CurrentKeyword)
{
case "red" :
red = reader.CurrentParameter;
break;
case "green" :
green = reader.CurrentParameter;
break;
case "blue" :
blue = reader.CurrentParameter;
break;
case ";" :
if(red >= 0 && green >= 0 && blue >= 0)
{
Color color = Color.FromArgb(255, red, green, blue);
this.colorTable.Add(color);
red = -1;
green = -1;
blue = -1;
}
break;
}
}
if(red >= 0 && green >= 0 && blue >= 0)
{
Color color = Color.FromArgb(255, red, green, blue);
this.colorTable.Add(color);
}
}
#endregion
#region 문서 정보 읽기 - ReadDocumentInfo(reader)
/// <summary>
/// 문서 정보 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
private void ReadDocumentInfo(RTFReader reader)
{
this.documentInfo.Clear();
int level = 0;
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
level++;
}
else if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
level--;
if(level < 0)
{
break;
}
}
else
{
switch(reader.CurrentKeyword)
{
case "creatim" :
this.documentInfo.CreateTime = ReadDateTime(reader);
level--;
break;
case "revtim" :
this.documentInfo.UpdateTime = ReadDateTime(reader);
level--;
break;
case "printim" :
this.documentInfo.PrintTime = ReadDateTime(reader);
level--;
break;
case "buptim" :
this.documentInfo.BackupTime = ReadDateTime(reader);
level--;
break;
default :
if(reader.CurrentKeyword != null)
{
if(reader.HasCurrentParameter)
{
this.documentInfo.SetInfo(reader.CurrentKeyword, reader.CurrentParameter.ToString());
}
else
{
this.documentInfo.SetInfo(reader.CurrentKeyword, ReadInnerText(reader, true));
}
}
break;
}
}
}
}
#endregion
#region 날짜/시간 읽기 - ReadDateTime(reader)
/// <summary>
/// 날짜/시간 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
/// <returns>날짜/시간</returns>
private DateTime ReadDateTime(RTFReader reader)
{
int year = 1900;
int month = 1;
int day = 1;
int hour = 0;
int minute = 0;
int second = 0;
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
break;
}
switch(reader.CurrentKeyword)
{
case "yr" : year = reader.CurrentParameter; break;
case "mo" : month = reader.CurrentParameter; break;
case "dy" : day = reader.CurrentParameter; break;
case "hr" : hour = reader.CurrentParameter; break;
case "min" : minute = reader.CurrentParameter; break;
case "sec" : second = reader.CurrentParameter; break;
}
}
return new DateTime(year, month, day, hour, minute, second);
}
#endregion
#region DOM 객체 읽기 - ReadDOMObject(reader, format)
/// <summary>
/// DOM 객체 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
/// <param name="format">문서 포맷 정보</param>
/// <returns>DOM 객체</returns>
private RTFDOMObject ReadDOMObject(RTFReader reader, RTFDocumentFormatInfo format)
{
RTFDOMObject domObject = new RTFDOMObject();
domObject.NativeLevel = reader.Level;
AddContentElement(domObject);
int levelBack = reader.Level;
while(reader.ReadToken() != null)
{
if(reader.Level < levelBack)
{
break;
}
if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
continue;
}
if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
continue;
}
if(reader.Level == domObject.NativeLevel + 1 && reader.CurrentKeyword.StartsWith("attribute_"))
{
domObject.CustomAttributeDictionary[reader.CurrentKeyword] = ReadInnerText(reader, true);
}
switch(reader.CurrentKeyword)
{
case RTFConstant.OBJAUTLINK :
domObject.ObjectType = RTFObjectType.AUTLINK;
break;
case RTFConstant.OBJCLASS :
domObject.ClassName = ReadInnerText(reader, true);
break;
case RTFConstant.OBJDATA :
string data = ReadInnerText(reader, true);
domObject.ContentByteArray = GetByteArray(data);
break;
case RTFConstant.OBJEMB :
domObject.ObjectType = RTFObjectType.EMB;
break;
case RTFConstant.OBJH :
domObject.Height = reader.CurrentParameter;
break;
case RTFConstant.OBJHTML :
domObject.ObjectType = RTFObjectType.HTML;
break;
case RTFConstant.OBJICEMB :
domObject.ObjectType = RTFObjectType.ICEMB;
break;
case RTFConstant.OBJLINK :
domObject.ObjectType = RTFObjectType.LINK;
break;
case RTFConstant.OBJNAME :
domObject.Name = ReadInnerText(reader, true);
break;
case RTFConstant.OBJOCX :
domObject.ObjectType = RTFObjectType.OCX;
break;
case RTFConstant.OBJPUB :
domObject.ObjectType = RTFObjectType.PUB;
break;
case RTFConstant.OBJSUB :
domObject.ObjectType = RTFObjectType.SUB;
break;
case RTFConstant.OBJTIME :
break;
case RTFConstant.OBJW :
domObject.Width = reader.CurrentParameter;
break;
case RTFConstant.OBJSCALEX :
domObject.ScaleX = reader.CurrentParameter;
break;
case RTFConstant.OBJSCALEY :
domObject.ScaleY = reader.CurrentParameter;
break;
case RTFConstant.RESULT :
RTFDOMElementContainer elementContainer = new RTFDOMElementContainer();
elementContainer.Name = RTFConstant.RESULT;
domObject.AppendChild(elementContainer);
Load(reader, format);
elementContainer.Locked = true;
break;
}
}
domObject.Locked = true;
return domObject;
}
#endregion
#region DOM 필드 읽기 - ReadDOMField(reader, format)
/// <summary>
/// DOM 필드 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
/// <param name="format">문서 포맷 정보</param>
/// <returns>DOM 필드</returns>
private RTFDOMField ReadDOMField(RTFReader reader, RTFDocumentFormatInfo format)
{
RTFDOMField field = new RTFDOMField();
field.NativeLevel = reader.Level;
AddContentElement(field);
int levelBack = reader.Level;
while(reader.ReadToken() != null)
{
if(reader.Level < levelBack)
{
break;
}
if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
}
else if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
}
else
{
switch(reader.CurrentKeyword)
{
case RTFConstant.FLDDIRTY :
field.Method = RTFDOMFieldMethod.DIRTY;
break;
case RTFConstant.FLDEDIT :
field.Method = RTFDOMFieldMethod.EDIT;
break;
case RTFConstant.FLDLOCK :
field.Method = RTFDOMFieldMethod.LOCK;
break;
case RTFConstant.FLDPRIV :
field.Method = RTFDOMFieldMethod.PRIV;
break;
case RTFConstant.FLDRSLT :
{
RTFDOMElementContainer elementContainer = new RTFDOMElementContainer();
elementContainer.Name = RTFConstant.FLDRSLT;
field.AppendChild(elementContainer);
Load(reader, format);
elementContainer.Locked = true;
break;
}
case RTFConstant.FLDINST :
{
RTFDOMElementContainer elementContainer = new RTFDOMElementContainer();
elementContainer.Name = RTFConstant.FLDINST;
field.AppendChild(elementContainer);
Load(reader, format);
elementContainer.Locked = true;
string text = elementContainer.InnerText;
if(text != null)
{
int index = text.IndexOf(RTFConstant.HYPERLINK);
if(index >= 0)
{
string link = null;
int index1 = text.IndexOf('\"', index);
if(index1 > 0 && text.Length > index1 + 2)
{
int index2 = text.IndexOf('\"', index1 + 2);
if(index2 > index1)
{
link = text.Substring(index1 + 1, index2 - index1 - 1);
if(format.Parent != null)
{
if(link.StartsWith("_Toc"))
{
link = "#" + link;
}
format.Parent.Link = link;
}
break;
}
}
}
}
break;
}
}
}
}
field.Locked = true;
return field;
}
#endregion
#region 내부 텍스트 읽기 - ReadInnerText(reader, firstToken, readSubsidaryLevel, breakMeetControlWord, htmlMode)
/// <summary>
/// 내부 텍스트 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
/// <param name="firstToken">첫번째 토큰</param>
/// <param name="readSubsidaryLevel">하위 레벨 읽기 여부</param>
/// <param name="breakMeetControlWord">제어 문자 발견시 브레이크 여부</param>
/// <param name="htmlMode">html 모드</param>
/// <returns>내부 텍스트</returns>
private string ReadInnerText(RTFReader reader, RTFToken firstToken, bool readSubsidaryLevel, bool breakMeetControlWord, bool htmlMode)
{
int level = 0;
RTFTextContainer textContainer = new RTFTextContainer(this);
textContainer.Accept(firstToken , reader);
while(true)
{
RTFTokenType tokenType = reader.PeekTokenType();
if(tokenType == RTFTokenType.EOF)
{
break;
}
if(tokenType == RTFTokenType.GroupStart)
{
level++;
}
else if(tokenType == RTFTokenType.GroupEnd)
{
level--;
if(level < 0)
{
break;
}
}
reader.ReadToken();
if(readSubsidaryLevel || level == 0)
{
if(htmlMode)
{
if(reader.CurrentKeyword == "par")
{
textContainer.Append(Environment.NewLine);
continue;
}
}
if(textContainer.Accept(reader.CurrentToken , reader))
{
continue;
}
else
{
if(breakMeetControlWord)
{
break;
}
}
}
}
return textContainer.Text;
}
#endregion
#region 내부 텍스트 읽기 - ReadInnerText(reader, readSubsidaryLevel)
/// <summary>
/// 내부 텍스트 읽기
/// </summary>
/// <param name="reader">RTF 리더</param>
/// <param name="readSubsidaryLevel">하위 레벨 읽기 여부</param>
/// <returns>내부 텍스트</returns>
private string ReadInnerText(RTFReader reader, bool readSubsidaryLevel)
{
return ReadInnerText(reader, null, readSubsidaryLevel, false, false);
}
#endregion
}
}
▶ RTFDOMElement.cs
using System;
using System.ComponentModel;
using System.Text;
using System.Xml.Serialization;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 엘리먼트
/// </summary>
public abstract class RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region Field
/// <summary>
/// 네이티브 레벨
/// </summary>
[NonSerialized]
internal int NativeLevel = -1;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// RTF 특성 리스트
/// </summary>
private RTFAttributeList attributeList = new RTFAttributeList();
/// <summary>
/// RTF DOM 엘리먼트 리스트
/// </summary>
private RTFDOMElementList elementList = new RTFDOMElementList();
/// <summary>
/// 소유자 RTF DOM 문서
/// </summary>
private RTFDOMDocument ownerDocument = null;
/// <summary>
/// 부모 RTF DOM 엘리먼트
/// </summary>
private RTFDOMElement parentElement = null;
/// <summary>
/// 잠금 여부
/// </summary>
private bool locked = false;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 특성 리스트 - AttributeList
/// <summary>
/// 특성 리스트
/// </summary>
public RTFAttributeList AttributeList
{
get
{
return this.attributeList;
}
set
{
this.attributeList = value;
}
}
#endregion
#region 엘리먼트 리스트 - ElementList
/// <summary>
/// 엘리먼트 리스트
/// </summary>
public RTFDOMElementList ElementList
{
get
{
return this.elementList;
}
}
#endregion
#region 소유자 문서 - OwnerDocument
/// <summary>
/// 소유자 문서
/// </summary>
[Browsable(false)]
[XmlIgnore]
public RTFDOMDocument OwnerDocument
{
get
{
return this.ownerDocument;
}
set
{
this.ownerDocument = value;
foreach(RTFDOMElement element in ElementList)
{
element.OwnerDocument = value;
}
}
}
#endregion
#region 부모 엘리먼트 - ParentElement
/// <summary>
/// 부모 엘리먼트
/// </summary>
[Browsable(false)]
public RTFDOMElement ParentElement
{
get
{
return this.parentElement;
}
}
#endregion
#region 내부 텍스트 - InnerText
/// <summary>
/// 내부 텍스트
/// </summary>
[Browsable(false)]
public virtual string InnerText
{
get
{
StringBuilder stringBuilder = new StringBuilder();
if(this.elementList != null)
{
foreach(RTFDOMElement element in this.elementList)
{
stringBuilder.Append(element.InnerText);
}
}
return stringBuilder.ToString();
}
}
#endregion
#region 잠금 여부 - Locked
/// <summary>
/// 잠금 여부
/// </summary>
[XmlIgnore]
[Browsable(false)]
public bool Locked
{
get
{
return this.locked;
}
set
{
this.locked = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 특성 소유 여부 구하기 - HasAttribute(name)
/// <summary>
/// 특성 소유 여부 구하기
/// </summary>
/// <param name="name">명칭</param>
/// <returns>특성 소유 여부</returns>
public bool HasAttribute(string name)
{
return this.attributeList.Contains(name);
}
#endregion
#region 특성 값 구하기 - GetAttributeValue(name, defaultValue)
/// <summary>
/// 특성 값 구하기
/// </summary>
/// <param name="name">명칭</param>
/// <param name="defaultValue">디폴트 값</param>
/// <returns>특성 값</returns>
public int GetAttributeValue(string name, int defaultValue)
{
if(this.attributeList.Contains(name))
{
return this.attributeList[name];
}
else
{
return defaultValue;
}
}
#endregion
#region 자식 추가하기 - AppendChild(element)
/// <summary>
/// 자식 추가하기
/// </summary>
/// <param name="element">엘리먼트</param>
/// <returns>인덱스</returns>
public int AppendChild(RTFDOMElement element)
{
CheckLocked();
element.parentElement = this;
element.OwnerDocument = this.ownerDocument;
return this.elementList.Add(element);
}
#endregion
#region 특성 설정하기 - SetAttribute(name, value)
/// <summary>
/// 특성 설정하기
/// </summary>
/// <param name="name">명칭</param>
/// <param name="value">값</param>
public void SetAttribute(string name, int value)
{
CheckLocked();
this.attributeList[name] = value;
}
#endregion
#region 잠금 여부 설정하기 - SetLockedDeeply(locked)
/// <summary>
/// 잠금 여부 설정하기
/// </summary>
/// <param name="locked">잠금 여부</param>
public void SetLockedDeeply(bool locked)
{
this.locked = locked;
if(this.elementList != null)
{
foreach(RTFDOMElement element in this.elementList)
{
element.SetLockedDeeply(locked);
}
}
}
#endregion
#region DOM 문자열 구하기 - GetDOMString()
/// <summary>
/// DOM 문자열 구하기
/// </summary>
/// <returns>DOM 문자열</returns>
public virtual string GetDOMString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(ToString());
GetDOMString(ElementList, stringBuilder, 1);
return stringBuilder.ToString();
}
#endregion
#region DOM 문자열 인쇄하기 - PrintDOMString()
/// <summary>
/// DOM 문자열 인쇄하기
/// </summary>
public void PrintDOMString()
{
Console.WriteLine(GetDOMString());
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region DOM 문자열 구하기 - GetDOMString(elementList, stringBuilder, level)
/// <summary>
/// DOM 문자열 구하기
/// </summary>
/// <param name="elementList">엘리먼트 리스트</param>
/// <param name="stringBuilder">문자열 빌더</param>
/// <param name="level">레벨</param>
protected void GetDOMString(RTFDOMElementList elementList, StringBuilder stringBuilder, int level)
{
foreach(RTFDOMElement element in elementList)
{
stringBuilder.Append(Environment.NewLine);
stringBuilder.Append(new string(' ' , level * 4));
stringBuilder.Append(element.ToString());
GetDOMString(element.ElementList, stringBuilder, level + 1);
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 잠금 여부 체크하기 - CheckLocked()
/// <summary>
/// 잠금 여부 체크하기
/// </summary>
private void CheckLocked()
{
if(this.locked)
{
throw new InvalidOperationException("Element locked");
}
}
#endregion
}
}
▶ RTFDOMElementContainer.cs
using System;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 엘리먼트 컨테이너
/// </summary>
[Serializable]
public class RTFDOMElementContainer : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 명칭
/// </summary>
private string name = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 명칭 - Name
/// <summary>
/// 명칭
/// </summary>
[DefaultValue( null )]
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMElementContainer()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMElementContainer()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return "Container:" + this.name;
}
#endregion
}
}
▶ RTFDOMElementList.cs
using System;
using System.Collections;
using System.Diagnostics;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 엘리먼트 리스트
/// </summary>
[Serializable]
[DebuggerTypeProxy(typeof(RTFInstanceDebugView))]
public class RTFDOMElementList : CollectionBase
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱서 - this[index]
/// <summary>
/// 인덱서
/// </summary>
/// <param name="index">인덱스</param>
/// <returns>RTF DOM 엘리먼트</returns>
public RTFDOMElement this[int index]
{
get
{
return (RTFDOMElement)List[index];
}
}
#endregion
#region 마지막 엘리먼트 - LastElement
/// <summary>
/// 마지막 엘리먼트
/// </summary>
public RTFDOMElement LastElement
{
get
{
if(Count > 0)
{
return (RTFDOMElement)List[Count - 1];
}
else
{
return null;
}
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMElementList()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMElementList()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 추가하기 - Add(element)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="element">RTF DOM 엘리먼트</param>
/// <returns>인덱스</returns>
public int Add(RTFDOMElement element)
{
return List.Add(element);
}
#endregion
#region 삽입하기 - Insert(index, element)
/// <summary>
/// 삽입하기
/// </summary>
/// <param name="index">인덱스</param>
/// <param name="element">RTF DOM 엘리먼트</param>
public void Insert(int index, RTFDOMElement element)
{
List.Insert(index, element);
}
#endregion
#region 제거하기 - Remove(element)
/// <summary>
/// 제거하기
/// </summary>
/// <param name="element">RTF DOM 엘리먼트</param>
public void Remove(RTFDOMElement element)
{
List.Remove(element);
}
#endregion
#region 인덱스 구하기 - GetIndex(element)
/// <summary>
/// 인덱스 구하기
/// </summary>
/// <param name="element">엘리먼트</param>
/// <returns>인덱스</returns>
public int GetIndex(RTFDOMElement element)
{
return List.IndexOf(element);
}
#endregion
#region 배열 구하기 - ToArray()
/// <summary>
/// 배열 구하기
/// </summary>
/// <returns>RTF DOM 엘리먼트 배열</returns>
public RTFDOMElement[] ToArray()
{
return (RTFDOMElement[])InnerList.ToArray(typeof(RTFDOMElement));
}
#endregion
}
}
▶ RTFDOMField.cs
using System;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 필드
/// </summary>
[Serializable]
public class RTFDOMField : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// RTF DOM 필드 메소드
/// </summary>
private RTFDOMFieldMethod method = RTFDOMFieldMethod.NONE;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 메소드 - Method
/// <summary>
/// 메소드
/// </summary>
[DefaultValue(RTFDOMFieldMethod.NONE)]
public RTFDOMFieldMethod Method
{
get
{
return this.method;
}
set
{
this.method = value;
}
}
#endregion
#region 지시 - Instructions
/// <summary>
/// 지시
/// </summary>
[DefaultValue(null)]
public string Instructions
{
get
{
foreach(RTFDOMElement element in ElementList)
{
if(element is RTFDOMElementContainer)
{
RTFDOMElementContainer container = (RTFDOMElementContainer)element;
if(container.Name == RTFConstant.FLDINST)
{
return container.InnerText;
}
}
}
return null;
}
}
#endregion
#region 결과 - Result
/// <summary>
/// 결과
/// </summary>
[DefaultValue(null)]
public RTFDOMElementContainer Result
{
get
{
foreach(RTFDOMElement element in this.ElementList)
{
if(element is RTFDOMElementContainer)
{
RTFDOMElementContainer container = (RTFDOMElementContainer)element;
if(container.Name == RTFConstant.FLDRSLT)
{
return container;
}
}
}
return null;
}
}
#endregion
#region 결과 문자열 - ResultString
/// <summary>
/// 결과 문자열
/// </summary>
public string ResultString
{
get
{
RTFDOMElementContainer container = this.Result;
if(container != null)
{
return container.InnerText;
}
else
{
return null;
}
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMField()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMField()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return "Field";
}
#endregion
}
}
▶ RTFDOMFieldMethod.cs
namespace TestLibrary
{
/// <summary>
/// RTF DOM 필드 메소드
/// </summary>
public enum RTFDOMFieldMethod
{
/// <summary>
/// NONE
/// </summary>
NONE,
/// <summary>
/// DIRTY
/// </summary>
DIRTY,
/// <summary>
/// EDIT
/// </summary>
EDIT,
/// <summary>
/// LOCK
/// </summary>
LOCK,
/// <summary>
/// PRIV
/// </summary>
PRIV
}
}
▶ RTFDOMFooter.cs
using System;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 바닥글
/// </summary>
[Serializable]
public class RTFDOMFooter : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 스타일
/// </summary>
private HeaderFooterStyle style = HeaderFooterStyle.ALL_PAGES;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 스타일 - Style
/// <summary>
/// 스타일
/// </summary>
[DefaultValue(HeaderFooterStyle.ALL_PAGES)]
public HeaderFooterStyle Style
{
get
{
return this.style;
}
set
{
this.style = value;
}
}
#endregion
#region 컨텐트 엘리먼트 소유 여부 - HasContentElement
/// <summary>
/// 컨텐트 엘리먼트 소유 여부
/// </summary>
public bool HasContentElement
{
get
{
return RTFUtility.HasContentElement(this);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"Footer {Style}";
}
#endregion
}
}
▶ RTFDOMHeader.cs
using System;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 머리글
/// </summary>
[Serializable]
public class RTFDOMHeader : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 스타일
/// </summary>
private HeaderFooterStyle style = HeaderFooterStyle.ALL_PAGES;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 스타일 - Style
/// <summary>
/// 스타일
/// </summary>
[DefaultValue(HeaderFooterStyle.ALL_PAGES)]
public HeaderFooterStyle Style
{
get
{
return this.style;
}
set
{
this.style = value;
}
}
#endregion
#region 컨텐트 엘리먼트 소유 여부 - HasContentElement
/// <summary>
/// 컨텐트 엘리먼트 소유 여부
/// </summary>
public bool HasContentElement
{
get
{
return RTFUtility.HasContentElement(this);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"Header {Style}";
}
#endregion
}
}
▶ RTFDOMImage.cs
using System;
using System.ComponentModel;
using System.Xml.Serialization;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 이미지
/// </summary>
[Serializable]
public class RTFDOMImage : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// ID
/// </summary>
private string id = null;
/// <summary>
/// 데이터
/// </summary>
private byte[] data = null;
/// <summary>
/// 스케일 X
/// </summary>
private int scaleX = 100;
/// <summary>
/// 스케일 Y
/// </summary>
private int scaleY = 100;
/// <summary>
/// 희망 너비
/// </summary>
private int desiredWidth = 0;
/// <summary>
/// 희망 높이
/// </summary>
private int desiredHeight = 0;
/// <summary>
/// 너비
/// </summary>
private int width = 0;
/// <summary>
/// 높이
/// </summary>
private int height = 0;
/// <summary>
/// RTF 그림 타입
/// </summary>
private RTFPictureType pictureType = RTFPictureType.JPEG;
/// <summary>
/// RTF 문서 포맷 정보
/// </summary>
private RTFDocumentFormatInfo format = new RTFDocumentFormatInfo();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region ID - ID
/// <summary>
/// ID
/// </summary>
[DefaultValue(null)]
public string ID
{
get
{
return this.id;
}
set
{
this.id = value;
}
}
#endregion
#region 데이터 - Data
/// <summary>
/// 데이터
/// </summary>
[Browsable(false)]
[XmlIgnore]
public byte[] Data
{
get
{
return this.data;
}
set
{
this.data = value;
}
}
#endregion
#region BASE64 데이터 - BASE64Data
/// <summary>
/// BASE64 데이터
/// </summary>
[Browsable(false)]
[XmlElement]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string BASE64Data
{
get
{
if(this.data == null)
{
return null;
}
else
{
return Convert.ToBase64String(this.data);
}
}
set
{
if(value != null && value.Length > 0)
{
this.data = Convert.FromBase64String(value);
}
else
{
this.data = null;
}
}
}
#endregion
#region 스케일 X - ScaleX
/// <summary>
/// 스케일 X
/// </summary>
[DefaultValue(100)]
public int ScaleX
{
get
{
return this.scaleX;
}
set
{
this.scaleX = value;
}
}
#endregion
#region 스케일 Y - ScaleY
/// <summary>
/// 스케일 Y
/// </summary>
[DefaultValue(100)]
public int ScaleY
{
get
{
return this.scaleY;
}
set
{
this.scaleY = value;
}
}
#endregion
#region 희망 너비 - DesiredWidth
/// <summary>
/// 희망 너비
/// </summary>
[DefaultValue(0)]
public int DesiredWidth
{
get
{
return this.desiredWidth;
}
set
{
this.desiredWidth = value;
}
}
#endregion
#region 희망 높이 - DesiredHeight
/// <summary>
/// 희망 높이
/// </summary>
[DefaultValue(0)]
public int DesiredHeight
{
get
{
return this.desiredHeight;
}
set
{
this.desiredHeight = value;
}
}
#endregion
#region 너비 - Width
/// <summary>
/// 너비
/// </summary>
[DefaultValue(0)]
public int Width
{
get
{
return this.width;
}
set
{
this.width = value;
}
}
#endregion
#region 높이 - Height
/// <summary>
/// 높이
/// </summary>
[DefaultValue(0)]
public int Height
{
get
{
return this.height;
}
set
{
this.height = value;
}
}
#endregion
#region 그림 타입 - PictureType
/// <summary>
/// 그림 타입
/// </summary>
public RTFPictureType PictureType
{
get
{
return this.pictureType;
}
set
{
this.pictureType = value;
}
}
#endregion
#region 문서 포맷 정보 - Format
/// <summary>
/// 문서 포맷 정보
/// </summary>
public RTFDocumentFormatInfo Format
{
get
{
return this.format;
}
set
{
this.format = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMImage()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMImage()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
string text = $"Image:{this.width}*{this.height}";
if(this.data != null && this.data.Length > 0)
{
text = $"{text} {Convert.ToDouble(this.data.Length / 1024.0).ToString("0.00")}KB";
}
return text;
}
#endregion
}
}
▶ RTFDOMLineBreak.cs
using System;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 라인 브레이크
/// </summary>
[Serializable]
public class RTFDOMLineBreak : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 내부 텍스트 - InnerText
/// <summary>
/// 내부 텍스트
/// </summary>
public override string InnerText
{
get
{
return Environment.NewLine;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMLineBreak()
/// <summary>
///
/// 생성자
/// </summary>
public RTFDOMLineBreak()
{
Locked = true;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return "linebreak";
}
#endregion
}
}
▶ RTFDOMObject.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 객체
/// </summary>
[Serializable]
public class RTFDOMObject : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 명칭
/// </summary>
private string name = null;
/// <summary>
/// 클래스명
/// </summary>
private string className = null;
/// <summary>
/// RTF 객체 타입
/// </summary>
private RTFObjectType objectType = RTFObjectType.EMB;
/// <summary>
/// 너비
/// </summary>
private int width = 0;
/// <summary>
/// 높이
/// </summary>
private int height = 0;
/// <summary>
/// 스케일 X
/// </summary>
private int scaleX = 100;
/// <summary>
/// 스케일 Y
/// </summary>
private int scaleY = 100;
/// <summary>
/// 컨텐트 바이트 배열
/// </summary>
private byte[] contentByteArray = null;
/// <summary>
/// 커스텀 특성 딕셔너리
/// </summary>
private Dictionary<string, string> customAttributeDictionary = new Dictionary<string, string>();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 명칭 - Name
/// <summary>
/// 명칭
/// </summary>
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
#endregion
#region 클래스명 - ClassName
/// <summary>
/// 클래스명
/// </summary>
public string ClassName
{
get
{
return this.className;
}
set
{
this.className = value;
}
}
#endregion
#region 객체 타입 - ObjectType
/// <summary>
/// 객체 타입
/// </summary>
public RTFObjectType ObjectType
{
get
{
return this.objectType;
}
set
{
this.objectType = value;
}
}
#endregion
#region 너비 - Width
/// <summary>
/// 너비
/// </summary>
public int Width
{
get
{
return this.width;
}
set
{
this.width = value;
}
}
#endregion
#region 높이 - Height
/// <summary>
/// 높이
/// </summary>
public int Height
{
get
{
return this.height;
}
set
{
this.height = value;
}
}
#endregion
#region 스케일 X - ScaleX
/// <summary>
/// 스케일 X
/// </summary>
public int ScaleX
{
get
{
return this.scaleX;
}
set
{
this.scaleX = value;
}
}
#endregion
#region 스케일 Y - ScaleY
/// <summary>
/// 스케일 Y
/// </summary>
public int ScaleY
{
get
{
return this.scaleY;
}
set
{
this.scaleY = value;
}
}
#endregion
#region 컨텐트 바이트 배열 - ContentByteArray
/// <summary>
/// 컨텐트 바이트 배열
/// </summary>
public byte[] ContentByteArray
{
get
{
return this.contentByteArray;
}
set
{
this.contentByteArray = value;
}
}
#endregion
#region 컨텐트 텍스트 - ContentText
/// <summary>
/// 컨텐트 텍스트
/// </summary>
[Browsable( false )]
public string ContentText
{
get
{
if(this.contentByteArray == null || this.contentByteArray.Length == 0)
{
return null;
}
else
{
return Encoding.Default.GetString(this.contentByteArray);
}
}
}
#endregion
#region 커스텀 특성 딕셔너리 - CustomAttributeDictionary
/// <summary>
/// 커스텀 특성 딕셔너리
/// </summary>
public Dictionary<string, string> CustomAttributeDictionary
{
get
{
if(this.customAttributeDictionary == null)
{
this.customAttributeDictionary = new Dictionary<string, string>();
}
return this.customAttributeDictionary;
}
set
{
this.customAttributeDictionary = value;
}
}
#endregion
#region 결과 - Result
/// <summary>
/// 결과
/// </summary>
[DefaultValue(null)]
public RTFDOMElementContainer Result
{
get
{
foreach(RTFDOMElement element in ElementList)
{
if(element is RTFDOMElementContainer)
{
RTFDOMElementContainer container = (RTFDOMElementContainer)element;
if(container.Name == RTFConstant.RESULT)
{
return container;
}
}
}
return null;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDomObject()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMObject()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
string text = $"Object:{this.Width}*{this.Height}";
if(this.contentByteArray != null && this.contentByteArray.Length > 0)
{
text = $"{text} {Convert.ToDouble(this.contentByteArray.Length / 1024.0).ToString("0.00")}KB";
}
return text;
}
#endregion
}
}
▶ RTFDomPageBreak.cs
using System;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 페이지 브레이크
/// </summary>
[Serializable]
public class RTFDOMPageBreak : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 내부 텍스트 - InnerText
/// <summary>
/// 내부 텍스트
/// </summary>
public override string InnerText
{
get
{
return string.Empty;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMPageBreak()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMPageBreak()
{
Locked = true;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return "page";
}
#endregion
}
}
▶ RTFDOMParagraph.cs
using System;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 문단
/// </summary>
[Serializable]
public class RTFDOMParagraph : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region Field
/// <summary>
/// 템플리트 생성 여부
/// </summary>
internal bool isTemplateGenerated = false;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// RTF 문서 포맷 정보
/// </summary>
private RTFDocumentFormatInfo format = new RTFDocumentFormatInfo();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 템플리트 생성 여부 - IsTemplateGenerated
/// <summary>
/// 템플리트 생성 여부
/// </summary>
public bool IsTemplateGenerated
{
get
{
return this.isTemplateGenerated;
}
}
#endregion
#region 문서 포맷 정보 - Format
/// <summary>
/// 문서 포맷 정보
/// </summary>
public RTFDocumentFormatInfo Format
{
get
{
return this.format;
}
set
{
this.format = value;
}
}
#endregion
#region 내부 텍스트 - InnerText
/// <summary>
/// 내부 텍스트
/// </summary>
public override string InnerText
{
get
{
return base.InnerText + Environment.NewLine;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMParagraph()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMParagraph()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Paragraph");
if(Format != null)
{
stringBuilder.Append($"({Format.TextAlignment})");
if(Format.ListID >= 0)
{
stringBuilder.Append($"ListID:{Format.ListID}");
}
}
return stringBuilder.ToString();
}
#endregion
}
}
▶ RTFDOMShape.cs
using System;
using System.ComponentModel ;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 도형
/// </summary>
[Serializable]
public class RTFDOMShape : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 도형 ID
/// </summary>
private int shapeID = 0;
/// <summary>
/// 왼쪽
/// </summary>
private int left = 0;
/// <summary>
/// 위쪽
/// </summary>
private int top = 0;
/// <summary>
/// 너비
/// </summary>
private int width = 0;
/// <summary>
/// 높이
/// </summary>
private int height = 0;
/// <summary>
/// Z 인덱스
/// </summary>
private int zIndex = 0;
/// <summary>
/// 문자열 특성 컬렉션
/// </summary>
private StringAttributeCollection attributeCollection = new StringAttributeCollection();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 도형 ID - ShapeID
/// <summary>
/// 도형 ID
/// </summary>
[DefaultValue(0)]
public int ShapeID
{
get
{
return this.shapeID;
}
set
{
this.shapeID = value;
}
}
#endregion
#region 왼쪽 - Left
/// <summary>
/// 왼쪽
/// </summary>
[DefaultValue(0)]
public int Left
{
get
{
return this.left;
}
set
{
this.left = value;
}
}
#endregion
#region 위쪽 - Top
/// <summary>
/// 위쪽
/// </summary>
[DefaultValue(0)]
public int Top
{
get
{
return this.top;
}
set
{
this.top = value;
}
}
#endregion
#region 너비 - Width
/// <summary>
/// 너비
/// </summary
[DefaultValue(0)]
public int Width
{
get
{
return this.width;
}
set
{
this.width = value;
}
}
#endregion
#region 높이 - Height
/// <summary>
/// 높이
/// </summary>
[DefaultValue(0)]
public int Height
{
get
{
return this.height;
}
set
{
this.height = value;
}
}
#endregion
#region Z 인덱스 - ZIndex
/// <summary>
/// Z 인덱스
/// </summary>
[DefaultValue(0)]
public int ZIndex
{
get
{
return this.zIndex;
}
set
{
this.zIndex = value;
}
}
#endregion
#region 문자열 특성 컬렉션 - AttrbuteCollection
/// <summary>
/// 문자열 특성 컬렉션
/// </summary>
public StringAttributeCollection AttrbuteCollection
{
get
{
return this.attributeCollection;
}
set
{
this.attributeCollection = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMShape()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMShape()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"Shape:Left:{this.left} Top:{this.top} Width:{this.width} Height:{this.height}";
}
#endregion
}
}
▶ RTFDOMShapeGroup.cs
using System;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 도형 그룹
/// </summary>
[Serializable]
public class RTFDOMShapeGroup : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 문자열 특성 컬렉션
/// </summary>
private StringAttributeCollection attributeCollection = new StringAttributeCollection();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 특성 컬렉션 - AttrbuteCollection
/// <summary>
/// 문자열 특성 컬렉션
/// </summary>
public StringAttributeCollection AttrbuteCollection
{
get
{
return this.attributeCollection;
}
set
{
this.attributeCollection = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMShapeGroup()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMShapeGroup()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return "ShapeGroup";
}
#endregion
}
}
▶ RTFDOMTable.cs
using System;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 테이블
/// </summary>
[Serializable]
public class RTFDOMTable : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 컬럼 리스트
/// </summary>
private RTFDOMElementList columnList = new RTFDOMElementList();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 컬럼 리스트 - ColumnList
/// <summary>
/// 컬럼 리스트
/// </summary>
public RTFDOMElementList ColumnList
{
get
{
return this.columnList;
}
set
{
this.columnList = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMTable()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMTable()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"Table(Rows:{this.ElementList.Count} Columns:{this.columnList.Count})";
}
#endregion
}
}
▶ RTFDOMTableCell.cs
using System;
using System.ComponentModel;
using System.Xml.Serialization;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 테이블 셀
/// </summary>
[Serializable]
public class RTFDOMTableCell : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 왼쪽
/// </summary>
private int left = 0;
/// <summary>
/// 너비
/// </summary>
private int width = 0;
/// <summary>
/// 높이
/// </summary>
private int height = 0;
/// <summary>
/// 행 범위
/// </summary>
private int rowSpan = 1;
/// <summary>
/// 열 범위
/// </summary>
private int columnSpan = 1;
/// <summary>
/// 패딩 왼쪽
/// </summary>
private int paddingLeft = int.MinValue;
/// <summary>
/// 패딩 위쪽
/// </summary>
private int paddingTop = int.MinValue;
/// <summary>
/// 패딩 오른쪽
/// </summary>
private int paddingRight = int.MinValue;
/// <summary>
/// 패딩 아래쪽
/// </summary>
private int paddingBottom = int.MinValue;
/// <summary>
/// 수직 정렬
/// </summary>
private RTFVerticalAlignment verticalAlignment = RTFVerticalAlignment.Top;
/// <summary>
/// 문서 포맷 정보
/// </summary>
private RTFDocumentFormatInfo format = new RTFDocumentFormatInfo();
/// <summary>
/// 멀티 라인 여부
/// </summary>
private bool multiline = true;
/// <summary>
/// 오버라이드 셀
/// </summary>
private RTFDOMTableCell overrideCell = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 왼쪽 - Left
/// <summary>
/// 왼쪽
/// </summary>
[DefaultValue(0)]
public int Left
{
get
{
return this.left;
}
set
{
this.left = value;
}
}
#endregion
#region 너비 - Width
/// <summary>
/// 너비
/// </summary>
[DefaultValue(0)]
public int Width
{
get
{
return this.width;
}
set
{
this.width = value;
}
}
#endregion
#region 높이 - Height
/// <summary>
/// 높이
/// </summary>
[DefaultValue(0)]
public int Height
{
get
{
return this.height;
}
set
{
this.height = value;
}
}
#endregion
#region 행 범위 - RowSpan
/// <summary>
/// 행 범위
/// </summary>
[DefaultValue(1)]
public int RowSpan
{
get
{
return this.rowSpan;
}
set
{
this.rowSpan = value;
}
}
#endregion
#region 열 범위 - ColumnSpan
/// <summary>
/// 열 범위
/// </summary>
[DefaultValue(1)]
public int ColumnSpan
{
get
{
return this.columnSpan;
}
set
{
this.columnSpan = value;
}
}
#endregion
#region 패딩 왼쪽 - PaddingLeft
/// <summary>
/// 패딩 왼쪽
/// </summary>
[DefaultValue(int.MinValue)]
public int PaddingLeft
{
get
{
return this.paddingLeft;
}
set
{
this.paddingLeft = value;
}
}
#endregion
#region 실행시 패딩 왼쪽 - RuntimePaddingLeft
/// <summary>
/// 실행시 패딩 왼쪽
/// </summary>
[Browsable(false)]
[XmlIgnore]
public int RuntimePaddingLeft
{
get
{
if(this.paddingLeft != int.MinValue)
{
return this.paddingLeft;
}
else if(ParentElement != null)
{
int padding = ((RTFDOMTableRow)ParentElement).PaddingLeft;
if(padding != int.MinValue)
{
return padding;
}
}
return 0;
}
}
#endregion
#region 패딩 위쪽 - PaddingTop
/// <summary>
/// 패딩 위쪽
/// </summary>
[DefaultValue(int.MinValue)]
public int PaddingTop
{
get
{
return this.paddingTop;
}
set
{
this.paddingTop = value;
}
}
#endregion
#region 실행시 패딩 위쪽 - RuntimePaddingTop
/// <summary>
/// 실행시 패딩 위쪽
/// </summary>
[Browsable(false)]
[XmlIgnore]
public int RuntimePaddingTop
{
get
{
if(this.paddingTop != int.MinValue)
{
return this.paddingTop;
}
else if(ParentElement != null)
{
int padding = ((RTFDOMTableRow)ParentElement).PaddingTop;
if(padding != int.MinValue)
{
return padding;
}
}
return 0;
}
}
#endregion
#region 패딩 오른쪽 - PaddingRight
/// <summary>
/// 패딩 오른쪽
/// </summary>
[DefaultValue(int.MinValue)]
public int PaddingRight
{
get
{
return this.paddingRight;
}
set
{
this.paddingRight = value;
}
}
#endregion
#region 실행시 패딩 오른쪽 - RuntimePaddingRight
/// <summary>
/// 실행시 패딩 오른쪽
/// </summary>
[Browsable(false)]
[XmlIgnore]
public int RuntimePaddingRight
{
get
{
if(this.paddingRight != int.MinValue)
{
return this.paddingRight;
}
else if(ParentElement != null)
{
int padding = ((RTFDOMTableRow)ParentElement).PaddingRight;
if(padding != int.MinValue)
{
return padding;
}
}
return 0;
}
}
#endregion
#region 패딩 아래쪽 - PaddingBottom
/// <summary>
/// 패딩 아래쪽
/// </summary>
[DefaultValue(int.MinValue)]
public int PaddingBottom
{
get
{
return this.paddingBottom;
}
set
{
this.paddingBottom = value;
}
}
#endregion
#region 실행시 패딩 아래쪽 - RuntimePaddingBottom
/// <summary>
/// 실행시 패딩 아래쪽
/// </summary>
[Browsable(false)]
[XmlIgnore]
public int RuntimePaddingBottom
{
get
{
if(this.paddingBottom != int.MinValue)
{
return this.paddingBottom;
}
else if(ParentElement != null)
{
int padding = ((RTFDOMTableRow)ParentElement).PaddingBottom;
if(padding != int.MinValue)
{
return padding;
}
}
return 0;
}
}
#endregion
#region 수직 정렬 - VerticalAlignment
/// <summary>
/// 수직 정렬
/// </summary>
[DefaultValue(RTFVerticalAlignment.Top)]
public RTFVerticalAlignment VerticalAlignment
{
get
{
return this.verticalAlignment;
}
set
{
this.verticalAlignment = value;
}
}
#endregion
#region 문서 포맷 정보 - Format
/// <summary>
/// 문서 포맷 정보
/// </summary>
public RTFDocumentFormatInfo Format
{
get
{
return this.format;
}
set
{
this.format = value;
}
}
#endregion
#region 멀티 라인 여부 - Multiline
/// <summary>
/// 멀티 라인 여부
/// </summary>
[DefaultValue(false)]
public bool Multiline
{
get
{
return this.multiline;
}
set
{
this.multiline = value;
}
}
#endregion
#region 오버라이드 셀 - OverrideCell
/// <summary>
/// 오버라이드 셀
/// </summary>
[Browsable(false)]
[XmlIgnore]
public RTFDOMTableCell OverrideCell
{
get
{
return this.overrideCell;
}
set
{
this.overrideCell = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMTableCell()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMTableCell()
{
this.format.BorderWidth = 1;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
if(this.overrideCell == null)
{
if(this.rowSpan != 1 || this.columnSpan != 1)
{
return $"Cell: RowSpan:{this.rowSpan} ColSpan:{this.columnSpan} Width:{this.Width}";
}
else
{
return $"Cell:Width:{this.Width}";
}
}
else
{
return "Cell:Overrided";
}
}
#endregion
}
}
▶ RTFDomTableColumn.cs
using System;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 테이블 컬럼
/// </summary>
[Serializable]
public class RTFDomTableColumn : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 너비
/// </summary>
private int width = 0;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 너비 - Width
/// <summary>
/// 너비
/// </summary>
[DefaultValue( 0 )]
public int Width
{
get
{
return this.width;
}
set
{
this.width = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDomTableColumn()
/// <summary>
/// 생성자
/// </summary>
public RTFDomTableColumn()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return "Column";
}
#endregion
}
}
▶ RTFDOMTableRow.cs
using System;
using System.ComponentModel;
using System.Collections;
using System.Xml.Serialization;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 테이블 행
/// </summary>
[Serializable]
public class RTFDOMTableRow : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 너비
/// </summary>
private int width = 0;
/// <summary>
/// 높이
/// </summary>
private int height = 0;
/// <summary>
/// 패딩 왼쪽
/// </summary>
private int paddingLeft = int.MinValue;
/// <summary>
/// 패딩 위쪽
/// </summary>
private int paddingTop = int.MinValue;
/// <summary>
/// 패딩 오른쪽
/// </summary>
private int paddingRight = int.MinValue;
/// <summary>
/// 패딩 아래쪽
/// </summary>
private int paddingBottom = int.MinValue;
/// <summary>
/// 셀 설정 리스트
/// </summary>
[NonSerialized]
private ArrayList cellSettingList = new ArrayList();
/// <summary>
/// RTF 문서 포맷 정보
/// </summary>
private RTFDocumentFormatInfo format = new RTFDocumentFormatInfo();
/// <summary>
/// 레벨
/// </summary>
private int level = 1;
/// <summary>
/// 행 인덱스
/// </summary>
private int rowIndex = 0;
/// <summary>
/// 마지막 행 여부
/// </summary>
private bool isLastRow = false;
/// <summary>
/// 머리글 여부
/// </summary>
private bool header = false;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 너비 - Width
/// <summary>
/// 너비
/// </summary>
[DefaultValue(0)]
public int Width
{
get
{
return this.width;
}
set
{
this.width = value;
}
}
#endregion
#region 높이 - Height
/// <summary>
/// 높이
/// </summary>
[DefaultValue(0)]
public int Height
{
get
{
return this.height;
}
set
{
this.height = value;
}
}
#endregion
#region 패딩 왼쪽 - PaddingLeft
/// <summary>
/// 패딩 왼쪽
/// </summary>
[DefaultValue(int.MinValue)]
public int PaddingLeft
{
get
{
return this.paddingLeft;
}
set
{
this.paddingLeft = value;
}
}
#endregion
#region 패딩 위쪽 - PaddingTop
/// <summary>
/// 패딩 위쪽
/// </summary>
[DefaultValue(int.MinValue)]
public int PaddingTop
{
get
{
return this.paddingTop;
}
set
{
this.paddingTop = value;
}
}
#endregion
#region 패딩 오른쪽 - PaddingRight
/// <summary>
/// 패딩 오른쪽
/// </summary>
[DefaultValue(int.MinValue)]
public int PaddingRight
{
get
{
return this.paddingRight;
}
set
{
this.paddingRight = value;
}
}
#endregion
#region 패딩 아래쪽 - PaddingBottom
/// <summary>
/// 패딩 아래쪽
/// </summary>
[DefaultValue(int.MinValue)]
public int PaddingBottom
{
get
{
return this.paddingBottom;
}
set
{
this.paddingBottom = value;
}
}
#endregion
#region 문서 포맷 정보 - Format
/// <summary>
/// 문서 포맷 정보
/// </summary>
public RTFDocumentFormatInfo Format
{
get
{
return this.format;
}
set
{
this.format = value;
}
}
#endregion
#region 레벨 - Level
/// <summary>
/// 레벨
/// </summary>
[DefaultValue(1)]
public int Level
{
get
{
return this.level;
}
set
{
this.level = value;
}
}
#endregion
#region 행 인덱스 - RowIndex
/// <summary>
/// 행 인덱스
/// </summary>
[DefaultValue(0)]
internal int RowIndex
{
get
{
return this.rowIndex;
}
set
{
this.rowIndex = value;
}
}
#endregion
#region 마지막 행 여부 - IsLastRow
/// <summary>
/// 마지막 행 여부
/// </summary>
[DefaultValue(false)]
public bool IsLastRow
{
get
{
return this.isLastRow;
}
set
{
this.isLastRow = value;
}
}
#endregion
#region 머리글 여부 - Header
/// <summary>
/// 머리글 여부
/// </summary>
[DefaultValue(false)]
public bool Header
{
get
{
return this.header;
}
set
{
this.header = value;
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region 셀 설정 리스트 - CellSettingList
/// <summary>
/// 셀 설정 리스트
/// </summary>
[Browsable(false)]
[XmlIgnore]
internal ArrayList CellSettingList
{
get
{
return this.cellSettingList;
}
set
{
this.cellSettingList = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMTableRow()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMTableRow()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"Row {this.rowIndex}";
}
#endregion
}
}
▶ RTFDOMText.cs
using System;
using System.ComponentModel;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF DOM 텍스트
/// </summary>
[Serializable]
public class RTFDOMText : RTFDOMElement
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// RTF 문서 포맷 정보
/// </summary>
private RTFDocumentFormatInfo format = new RTFDocumentFormatInfo();
/// <summary>
/// 텍스트
/// </summary>
private string text = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문서 포맷 정보 - Format
/// <summary>
/// 문서 포맷 정보
/// </summary>
public RTFDocumentFormatInfo Format
{
get
{
return this.format;
}
set
{
this.format = value;
}
}
#endregion
#region 텍스트 - Text
/// <summary>
/// 텍스트
/// </summary>
[DefaultValue( null)]
public string Text
{
get
{
return this.text;
}
set
{
this.text = value;
}
}
#endregion
#region 내부 텍스트 - InnerText
/// <summary>
/// 내부 텍스트
/// </summary>
public override string InnerText
{
get
{
return this.text;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFDOMText()
/// <summary>
/// 생성자
/// </summary>
public RTFDOMText()
{
Locked = true;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Text");
if(Format != null)
{
if(Format.Hidden)
{
stringBuilder.Append("(Hidden)");
}
}
stringBuilder.Append($":{this.text}");
return stringBuilder.ToString();
}
#endregion
}
}
▶ RTFFont.cs
using System.Collections.Generic;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF 폰트
/// </summary>
public class RTFFont
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 인코딩 딕셔너리
/// </summary>
private static Dictionary<int, Encoding> _encodingDictionary = null;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 인덱스
/// </summary>
private int index = 0;
/// <summary>
/// 폰트명
/// </summary>
private string name = null;
/// <summary>
/// 문자 세트
/// </summary>
private int characterSet = 1;
/// <summary>
/// 인코딩
/// </summary>
private Encoding encoding = null;
/// <summary>
/// NULL 여부
/// </summary>
private bool isNull = false;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱스 - Index
/// <summary>
/// 인덱스
/// </summary>
public int Index
{
get
{
return this.index;
}
set
{
this.index = value;
}
}
#endregion
#region 폰트명 - Name
/// <summary>
/// 폰트명
/// </summary>
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
#endregion
#region 문자 세트 - CharacterSet
/// <summary>
/// 문자 세트
/// </summary>
public int CharacterSet
{
get
{
return this.characterSet;
}
set
{
this.characterSet = value;
this.encoding = GetEncoding(this.characterSet);
}
}
#endregion
#region 인코딩 - Encoding
/// <summary>
/// 인코딩
/// </summary>
public Encoding Encoding
{
get
{
return this.encoding;
}
}
#endregion
#region NULL 여부 - IsNull
/// <summary>
/// NULL 여부
/// </summary>
public bool IsNull
{
get
{
return this.isNull;
}
set
{
this.isNull = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFFont(index, name)
/// <summary>
/// 생성자
/// </summary>
/// <param name="index"></param>
/// <param name="name"></param>
public RTFFont(int index, string name)
{
this.index = index;
this.name = name;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Internal
#region 문자 세트 구하기 - GetCharset(encoding)
/// <summary>
/// 문자 세트 구하기
/// </summary>
/// <param name="encoding">인코딩</param>
/// <returns>문자 세트</returns>
internal static int GetCharset(Encoding encoding)
{
CheckEncodingDictionary();
foreach(int key in _encodingDictionary.Keys)
{
if(_encodingDictionary[key] == encoding)
{
return key;
}
}
return 1;
}
#endregion
#region 인코딩 구하기 - GetEncoding(characterSet)
/// <summary>
/// 인코딩 구하기
/// </summary>
/// <param name="characterSet">문자 세트</param>
/// <returns>인코딩</returns>
internal static Encoding GetEncoding(int characterSet)
{
if(characterSet == 0)
{
return ANSIEncoding.Instance;
}
else if(characterSet == 1)
{
return Encoding.Default;
}
else
{
CheckEncodingDictionary();
if(_encodingDictionary.ContainsKey(characterSet))
{
return _encodingDictionary[characterSet];
}
else
{
return null;
}
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 인코딩 딕셔너리 체크하기 - CheckEncodingDictionary()
/// <summary>
/// 인코딩 딕셔너리 체크하기
/// </summary>
private static void CheckEncodingDictionary()
{
if(_encodingDictionary == null)
{
_encodingDictionary = new Dictionary<int, Encoding>();
//_encodingDictionary[ 0] = ANSIEncoding.Instance;
//_encodingDictionary[ 1] = Encoding.Default;
_encodingDictionary[ 77] = Encoding.GetEncoding(10000); // Mac ,macintosh
_encodingDictionary[128] = Encoding.GetEncoding(932 ); // Shift Jis ;ANSI/OEM - Japanese, Shift-JIS
_encodingDictionary[130] = Encoding.GetEncoding(1361 ); // Johab;Korean (Johab)
_encodingDictionary[134] = Encoding.GetEncoding(936 ); // GB2312
_encodingDictionary[136] = Encoding.GetEncoding(10002); // Big5
_encodingDictionary[161] = Encoding.GetEncoding(1253 ); // Greek
_encodingDictionary[162] = Encoding.GetEncoding(1254 ); // Turkish
_encodingDictionary[163] = Encoding.GetEncoding(1258 ); // Vietnamese;ANSI/OEM - Vietnamese
_encodingDictionary[177] = Encoding.GetEncoding(1255 ); // Hebrw
_encodingDictionary[178] = Encoding.GetEncoding(864 ); // Arabic
_encodingDictionary[179] = Encoding.GetEncoding(864 ); // Arabic Traditional
_encodingDictionary[180] = Encoding.GetEncoding(864 ); // Arabic user
_encodingDictionary[181] = Encoding.GetEncoding(864 ); // Hebrew user
_encodingDictionary[186] = Encoding.GetEncoding(775 ); // Baltic
_encodingDictionary[204] = Encoding.GetEncoding(866 ); // Russian
_encodingDictionary[222] = Encoding.GetEncoding(874 ); // Thai
_encodingDictionary[255] = Encoding.GetEncoding(437 ); // OEM
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 복제하기- Clone()
/// <summary>
/// 복제하기
/// </summary>
/// <returns>RTF 폰트</returns>
public RTFFont Clone()
{
RTFFont font = new RTFFont(this.index , this.name);
font.index = this.index;
font.name = this.name;
font.characterSet = this.characterSet;
font.encoding = this.encoding;
return font;
}
#endregion
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"{this.index}:{this.name} Charset:{this.characterSet}";
}
#endregion
}
}
▶ RTFFontTable.cs
using System;
using System.Collections;
using System.Diagnostics;
using System.Text ;
namespace TestLibrary
{
/// <summary>
/// RTF 폰트 테이블
/// </summary>
[DebuggerDisplay("Count={Count}")]
[DebuggerTypeProxy(typeof(RTFInstanceDebugView))]
public class RTFFontTable : CollectionBase
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱서 - this[index]
/// <summary>
/// 인덱서
/// </summary>
/// <param name="index">인덱스</param>
/// <returns>RTF 폰트</returns>
public RTFFont this[int index]
{
get
{
foreach(RTFFont font in this)
{
if(font.Index == index)
{
return font;
}
}
return null;
}
}
#endregion
#region 인덱서 - this[name]
/// <summary>
/// 인덱서
/// </summary>
/// <param name="name">폰트명</param>
/// <returns>RTF 폰트</returns>
public RTFFont this[string name]
{
get
{
foreach(RTFFont font in this)
{
if(font.Name == name)
{
return font;
}
}
return null;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFFontTable()
/// <summary>
/// 생성자
/// </summary>
public RTFFontTable()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 추가하기 - Add(font)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="font">폰트</param>
public void Add(RTFFont font)
{
List.Add(font);
}
#endregion
#region 추가하기 - Add(index, name, encoding)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="index">인덱스</param>
/// <param name="name">폰트명</param>
/// <param name="encoding">인코딩</param>
/// <returns>RTF 폰트</returns>
public RTFFont Add(int index, string name, Encoding encoding)
{
if(this[name] == null)
{
RTFFont font = new RTFFont(index, name);
if(encoding != null)
{
font.CharacterSet = RTFFont.GetCharset(encoding);
}
List.Add(font);
return font ;
}
return this[name];
}
#endregion
#region 추가하기 - Add(name)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="name">폰트명</param>
public RTFFont Add(string name)
{
return Add(Count, name, Encoding.Default);
}
#endregion
#region 추가하기 - Add(name, encoding)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="name">폰트명</param>
/// <param name="encoding">인코딩</param>
/// <returns>RTF 폰트</returns>
public RTFFont Add(string name, Encoding encoding)
{
return Add(Count, name, encoding);
}
#endregion
#region 제거하기 - Remove(name)
/// <summary>
/// 제거하기
/// </summary>
/// <param name="name">폰트명</param>
public void Remove(string name)
{
RTFFont font = this[name];
if(font != null)
{
List.Remove(font);
}
}
#endregion
#region 폰트명 구하기 - GetFontName(index)
/// <summary>
/// 폰트명 구하기
/// </summary>
/// <param name="index">인덱스</param>
/// <returns>폰트명</returns>
public string GetFontName(int index)
{
RTFFont font = this[index];
if(font != null)
{
return font.Name;
}
else
{
return null;
}
}
#endregion
#region 인덱스 구하기 - GetIndex(name)
/// <summary>
/// 인덱스 구하기
/// </summary>
/// <param name="name">폰트명</param>
/// <returns>인덱스</returns>
public int GetIndex(string name)
{
foreach(RTFFont font in this)
{
if(font.Name == name)
{
return font.Index;
}
}
return -1 ;
}
#endregion
#region 쓰기 - Write(writer)
/// <summary>
/// 쓰기
/// </summary>
/// <param name="writer">라이터</param>
public void Write(RTFWriter writer)
{
writer.WriteStartGroup();
writer.WriteKeyword(RTFConstant.FONTTBL);
foreach(RTFFont font in this)
{
writer.WriteStartGroup();
writer.WriteKeyword($"f{font.Index}");
if(font.CharacterSet != 0)
{
writer.WriteKeyword($"fcharset{font.CharacterSet}");
}
writer.WriteText(font.Name);
writer.WriteEndGroup();
}
writer.WriteEndGroup();
}
#endregion
#region 복제하기 - Clone()
/// <summary>
/// 복제하기
/// </summary>
/// <returns>RTF 폰트 테이블</returns>
public RTFFontTable Clone()
{
RTFFontTable fontTable = new RTFFontTable();
foreach(RTFFont font in this)
{
RTFFont newFont = font.Clone();
fontTable.List.Add(newFont);
}
return fontTable;
}
#endregion
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
foreach(RTFFont font in this)
{
stringBuilder.Append(Environment.NewLine);
stringBuilder.Append($"Index {font.Index} Name:{font.Name}");
}
return stringBuilder.ToString();
}
#endregion
}
}
▶ RTFInstanceDebugView.cs
using System;
using System.Collections;
using System.Diagnostics;
namespace TestLibrary
{
/// <summary>
/// RTF 인스턴스 디버그 뷰
/// </summary>
public class RTFInstanceDebugView
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 인스턴스
/// </summary>
private object instance = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 항목 배열 - Items
/// <summary>
/// 항목 배열
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public object Items
{
get
{
if(this.instance is IEnumerable)
{
CollectionBase collection = (CollectionBase)this.instance;
object[] itemArray = new object[collection.Count];
int count = 0;
foreach(object item in collection)
{
itemArray[count] = item;
count++;
}
return itemArray;
}
else if(this.instance is RTFColorTable)
{
RTFColorTable table = (RTFColorTable)this.instance;
object[] itemArray = new object[table.Count];
for(int i = 0; i < table.Count; i++)
{
itemArray[i] = table[i];
}
return itemArray;
}
else if(this.instance is RTFDocumentInfo)
{
RTFDocumentInfo info = (RTFDocumentInfo)this.instance;
return info.ItemArray;
}
else
{
return this.instance;
}
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFInstanceDebugView(instance)
/// <summary>
/// 생성자
/// </summary>
/// <param name="instance">인스턴스</param>
public RTFInstanceDebugView(object instance)
{
if(instance == null)
{
throw new ArgumentNullException("instance");
}
this.instance = instance;
}
#endregion
}
}
▶ RTFLex.cs
using System;
using System.IO;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF 어휘 분석기
/// </summary>
public class RTFLex
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 리더
/// </summary>
private TextReader reader = null;
/// <summary>
/// EOF
/// </summary>
private const int EOF = -1 ;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFLex(reader)
/// <summary>
/// 생성자
/// </summary>
/// <param name="reader">리더</param>
public RTFLex(TextReader reader)
{
this.reader = reader;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 토큰 타입 엿보기 - PeekTokenType()
/// <summary>
/// 토큰 타입 엿보기
/// </summary>
/// <returns>토큰 타입</returns>
public RTFTokenType PeekTokenType()
{
int character = this.reader.Peek();
while(character == '\r' || character == '\n' || character == '\t' || character == '\0')
{
character = this.reader.Read();
character = this.reader.Peek();
}
if(character == EOF)
{
return RTFTokenType.EOF;
}
else
{
switch(character)
{
case '{' : return RTFTokenType.GroupStart;
case '}' : return RTFTokenType.GroupEnd;
case '\\' : return RTFTokenType.Control;
default : return RTFTokenType.Text;
}
}
}
#endregion
#region 다음 토큰 읽기 - ReadNextToken()
/// <summary>
/// 다음 토큰 읽기
/// </summary>
/// <returns>다음 토큰</returns>
public RTFToken ReadNextToken()
{
RTFToken token = new RTFToken();
int character = this.reader.Read();
if(character == '\"')
{
StringBuilder stringBuilder = new StringBuilder();
while(true)
{
character = this.reader.Read();
if(character < 0)
{
break;
}
if(character == '\"')
{
break;
}
else
{
stringBuilder.Append((char)character);
}
}
token.TokenType = RTFTokenType.Text;
token.Keyword = stringBuilder.ToString();
return token;
}
while(character == '\r' || character == '\n' || character == '\t' || character == '\0' )
{
character = this.reader.Read();
}
if(character != EOF)
{
switch(character)
{
case '{' :
token.TokenType = RTFTokenType.GroupStart;
break;
case '}' :
token.TokenType = RTFTokenType.GroupEnd;
break;
case '\\' :
ParseKeyword(token);
break;
default:
token.TokenType = RTFTokenType.Text;
ParseText(character, token);
break;
}
}
else
{
token.TokenType = RTFTokenType.EOF;
}
return token ;
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 키워드 파싱하기 - ParseKeyword(token)
/// <summary>
/// 키워드 파싱하기
/// </summary>
/// <param name="token">토큰</param>
private void ParseKeyword(RTFToken token)
{
bool extended = false;
int character = this.reader.Peek();
if(char.IsLetter((char)character) == false)
{
this.reader.Read();
if(character == '*')
{
token.TokenType = RTFTokenType.Keyword;
this.reader.Read();
extended = true;
goto READ_KEYWORD;
}
else if(character == '\\' || character == '{' || character == '}')
{
token.TokenType = RTFTokenType.Text;
token.Keyword = ((char)character).ToString();
}
else
{
token.TokenType = RTFTokenType.Control;
token.Keyword = ((char)character).ToString();
if(token.Keyword == "\'")
{
StringBuilder textStringBuilder = new StringBuilder();
textStringBuilder.Append((char)this.reader.Read());
textStringBuilder.Append((char)this.reader.Read());
token.HasParameter = true;
token.Parameter = Convert.ToInt32(textStringBuilder.ToString().ToLower(), 16);
if(token.Parameter == 0)
{
token.Parameter = 0;
}
}
}
return;
}
READ_KEYWORD :
StringBuilder keywordStringBuilder = new StringBuilder();
character = this.reader.Peek();
while(char.IsLetter((char)character))
{
this.reader.Read();
keywordStringBuilder.Append((char)character);
character = this.reader.Peek();
}
if(extended)
{
token.TokenType = RTFTokenType.ExtendedKeyword;
}
else
{
token.TokenType = RTFTokenType.Keyword;
}
token.Keyword = keywordStringBuilder.ToString();
if(char.IsDigit((char)character) || character == '-')
{
token.HasParameter = true;
bool negative = false;
if(character == '-')
{
negative = true;
this.reader.Read();
}
character = this.reader.Peek();
StringBuilder textStringBuilder = new StringBuilder();
while(char.IsDigit((char)character))
{
this.reader.Read();
textStringBuilder.Append((char)character);
character = this.reader.Peek();
}
int parameter = Convert.ToInt32(textStringBuilder.ToString());
if(negative)
{
parameter = - parameter;
}
token.Parameter = parameter;
}
if(character == ' ')
{
this.reader.Read();
}
}
#endregion
#region 공백 문자 지우기 - ClearWhitespace()
/// <summary>
/// 공백 문자 지우기
/// </summary>
/// <returns>문자</returns>
private int ClearWhitespace()
{
int character = this.reader.Peek();
while(character == '\r' || character == '\n' || character == '\t' || character == '\0')
{
this.reader.Read();
character = this.reader.Peek();
}
return character;
}
#endregion
#region 텍스트 파싱하기 - ParseText(character, token)
/// <summary>
/// 텍스트 파싱하기
/// </summary>
/// <param name="character">문자</param>
/// <param name="token">토큰</param>
private void ParseText(int character, RTFToken token)
{
StringBuilder stringBuilder = new StringBuilder(((char)character).ToString());
character = ClearWhitespace();
while(character != '\\' && character != '}' && character != '{' && character != EOF)
{
this.reader.Read();
stringBuilder.Append((char)character);
character = ClearWhitespace();
}
token.Keyword = stringBuilder.ToString();
}
#endregion
}
}
▶ RTFList.cs
using System;
namespace TestLibrary
{
/// <summary>
/// RTF 리스트
/// </summary>
public class RTFList
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 리스트 ID
/// </summary>
private int listID = 0;
/// <summary>
/// 리스트명
/// </summary>
private string listName = null;
/// <summary>
/// 리스트 템플리트 ID
/// </summary>
private int listTemplateID = 0;
/// <summary>
/// 리스트 SIMPLE 여부
/// </summary>
private bool listSimple = false;
/// <summary>
/// 리스트 HYBRID 여부
/// </summary>
private bool listHybrid = false;
/// <summary>
/// 리스트 스타일명
/// </summary>
private string listStyleName = null;
/// <summary>
/// 시작 레벨
/// </summary>
private int levelStartAt = 1;
/// <summary>
/// NFC 레벨 번호 타입
/// </summary>
private LevelNumberType nfcLevelNumberType = LevelNumberType.NONE ;
/// <summary>
/// JC 레벨
/// </summary>
private int jcLevel = 0;
/// <summary>
/// 레벨 팔로우
/// </summary>
private int levelFollow = 0;
/// <summary>
/// 폰트명
/// </summary>
private string fontName = null;
/// <summary>
/// 레벨 텍스트
/// </summary>
private string levelText = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 리스트 ID - ListID
/// <summary>
/// 리스트 ID
/// </summary>
public int ListID
{
get
{
return this.listID;
}
set
{
this.listID = value;
}
}
#endregion
#region 리스트명 - ListName
/// <summary>
/// 리스트명
/// </summary>
public string ListName
{
get
{
return this.listName;
}
set
{
this.listName = value;
}
}
#endregion
#region 리스트 템플리트 ID - ListTemplateID
/// <summary>
/// 리스트 템플리트 ID
/// </summary>
public int ListTemplateID
{
get
{
return this.listTemplateID;
}
set
{
this.listTemplateID = value;
}
}
#endregion
#region 리스트 SIMPLE 여부 - ListSimple
/// <summary>
/// 리스트 SIMPLE 여부
/// </summary>
public bool ListSimple
{
get
{
return this.listSimple;
}
set
{
this.listSimple = value;
}
}
#endregion
#region 리스트 HYBRID 여부 - ListHybrid
/// <summary>
/// 리스트 HYBRID 여부
/// </summary>
public bool ListHybrid
{
get
{
return this.listHybrid;
}
set
{
this.listHybrid = value;
}
}
#endregion
#region 리스트 스타일명 - ListStyleName
/// <summary>
/// 리스트 스타일명
/// </summary>
public string ListStyleName
{
get
{
return this.listStyleName;
}
set
{
this.listStyleName = value;
}
}
#endregion
#region 시작 레벨 - LevelStartAt
/// <summary>
/// 시작 레벨
/// </summary>
public int LevelStartAt
{
get
{
return this.levelStartAt;
}
set
{
this.levelStartAt = value;
}
}
#endregion
#region NFC 레벨 번호 타입 - NFCLevelNumberType
/// <summary>
/// NFC 레벨 번호 타입
/// </summary>
public LevelNumberType NFCLevelNumberType
{
get
{
return this.nfcLevelNumberType;
}
set
{
this.nfcLevelNumberType = value;
}
}
#endregion
#region JC 레벨 - JCLevel
/// <summary>
/// JC 레벨
/// </summary>
public int JCLevel
{
get
{
return this.jcLevel;
}
set
{
this.jcLevel = value;
}
}
#endregion
#region 레벨 팔로우 - LevelFollow
/// <summary>
/// 레벨 팔로우
/// </summary>
public int LevelFollow
{
get
{
return this.levelFollow;
}
set
{
this.levelFollow = value;
}
}
#endregion
#region 폰트명 - FontName
/// <summary>
/// 폰트명
/// </summary>
public string FontName
{
get
{
return this.fontName;
}
set
{
this.fontName = value;
}
}
#endregion
#region 레벨 텍스트 - LevelText
/// <summary>
/// 레벨 텍스트
/// </summary>
public string LevelText
{
get
{
return this.levelText;
}
set
{
this.levelText = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
if(NFCLevelNumberType == LevelNumberType.BULLET)
{
string text = $"ID:{ListID} Bullet:";
if(string.IsNullOrEmpty(LevelText) == false)
{
text = $"{text}({Convert.ToString((short)this.LevelText[0])})";
}
return text;
}
else
{
return $"ID:{ListID} {NFCLevelNumberType.ToString()} Start:{LevelStartAt}";
}
}
#endregion
}
}
▶ RTFListOverride.cs
namespace TestLibrary
{
/// <summary>
/// RTF 리스트 오버라이드
/// </summary>
public class RTFListOverride
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// ID
/// </summary>
private int id = 1;
/// <summary>
/// 리스트 ID
/// </summary>
private int listID = 0;
/// <summary>
/// 리스트 오버라이드 카운트
/// </summary>
private int listOverriedCount = 0;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region ID - ID
/// <summary>
/// ID
/// </summary>
public int ID
{
get
{
return this.id;
}
set
{
this.id = value;
}
}
#endregion
#region 리스트 ID - ListID
/// <summary>
/// 리스트 ID
/// </summary>
public int ListID
{
get
{
return this.listID;
}
set
{
this.listID = value;
}
}
#endregion
#region 리스트 오버라이드 카운트 - ListOverriedCount
/// <summary>
/// 리스트 오버라이드 카운트
/// </summary>
public int ListOverriedCount
{
get
{
return this.listOverriedCount;
}
set
{
this.listOverriedCount = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"ID:{ID} ListID:{ListID} Count:{ListOverriedCount}";
}
#endregion
}
}
▶ RTFListOverrideTable.cs
using System.Collections.Generic;
namespace TestLibrary
{
/// <summary>
/// RTF 리스트 오버라이드 테이블
/// </summary>
public class RTFListOverrideTable : List<RTFListOverride>
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFListOverrideTable()
/// <summary>
/// 생성자
/// </summary>
public RTFListOverrideTable()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region ID로 구하기 - GetByID(id)
/// <summary>
/// ID로 구하기
/// </summary>
/// <param name="id">ID</param>
/// <returns>RTF 리스트 오버라이드</returns>
public RTFListOverride GetByID(int id)
{
foreach(RTFListOverride item in this)
{
if(item.ID == id)
{
return item;
}
}
return null;
}
#endregion
}
}
▶ RTFListTable.cs
using System.Collections.Generic;
namespace TestLibrary
{
/// <summary>
/// RTF 리스트 테이블
/// </summary>
public class RTFListTable : List<RTFList>
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFListTable()
/// <summary>
/// 생성자
/// </summary>
public RTFListTable()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region ID로 구하기 - GetByID(id)
/// <summary>
/// ID로 구하기
/// </summary>
/// <param name="id">ID</param>
/// <returns>RTF 리스트</returns>
public RTFList GetByID(int id)
{
foreach(RTFList list in this)
{
if(list.ListID == id)
{
return list;
}
}
return null;
}
#endregion
}
}
▶ RTFNode.cs
namespace TestLibrary
{
/// <summary>
/// RTF 노드
/// </summary>
public class RTFNode
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region Field
/// <summary>
/// 노드 타입
/// </summary>
protected RTFNodeType nodeType = RTFNodeType.NONE;
/// <summary>
/// 부모
/// </summary>
protected RTFNodeGroup parent = null;
/// <summary>
/// 소유자 문서
/// </summary>
protected RTFRawDocument ownerDocument = null ;
/// <summary>
/// 키워드
/// </summary>
protected string keyword = null;
/// <summary>
/// 매개 변수 소유 여부
/// </summary>
protected bool hasParameter = false;
/// <summary>
/// 매개 변수
/// </summary>
protected int parameter = 0;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱스 - Index
/// <summary>
/// 인덱스
/// </summary>
public int Index
{
get
{
if(this.parent == null)
{
return 0;
}
else
{
return this.parent.ChildNodeList.GetIndex(this);
}
}
}
#endregion
#region 노드 타입 - NodeType
/// <summary>
/// 노드 타입
/// </summary>
public RTFNodeType NodeType
{
get
{
return this.nodeType;
}
}
#endregion
#region 부모 - Parent
/// <summary>
/// 부모
/// </summary>
public virtual RTFNodeGroup Parent
{
get
{
return this.parent;
}
set
{
this.parent = value;
}
}
#endregion
#region 이전 노드 - PreviousNode
/// <summary>
/// 이전 노드
/// </summary>
public RTFNode PreviousNode
{
get
{
if(this.parent != null)
{
int index = this.parent.ChildNodeList.GetIndex(this);
if(index > 0)
{
return this.parent.ChildNodeList[index - 1];
}
}
return null;
}
}
#endregion
#region 다음 노드 - NextNode
/// <summary>
/// 다음 노드
/// </summary>
public RTFNode NextNode
{
get
{
if(this.parent != null)
{
int index = this.parent.ChildNodeList.GetIndex(this);
if(index >= 0 && index < this.parent.ChildNodeList.Count - 1)
{
return this.parent.ChildNodeList[index + 1];
}
}
return null;
}
}
#endregion
#region 자식 노드 리스트 - ChildNodeList
/// <summary>
/// 자식 노드 리스트
/// </summary>
public virtual RTFNodeList ChildNodeList
{
get
{
return null;
}
}
#endregion
#region 소유자 문서 - OwnerDocument
/// <summary>
/// 소유자 문서
/// </summary>
public virtual RTFRawDocument OwnerDocument
{
get
{
return this.ownerDocument;
}
set
{
this.ownerDocument = value;
if(ChildNodeList != null)
{
foreach(RTFNode node in ChildNodeList)
{
node.OwnerDocument = value;
}
}
}
}
#endregion
#region 키워드 - Keyword
/// <summary>
/// 키워드
/// </summary>
public virtual string Keyword
{
get
{
return this.keyword;
}
set
{
this.keyword = value;
}
}
#endregion
#region 매개 변수 소유 여부 - HasParameter
/// <summary>
/// 매개 변수 소유 여부
/// </summary>
public virtual bool HasParameter
{
get
{
return this.hasParameter;
}
set
{
this.hasParameter = value;
}
}
#endregion
#region 매개 변수 - Parameter
/// <summary>
/// 매개 변수
/// </summary>
public virtual int Parameter
{
get
{
return this.parameter;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFNode()
/// <summary>
/// 생성자
/// </summary>
public RTFNode()
{
}
#endregion
#region 생성자 - RTFNode(token)
/// <summary>
/// 생성자
/// </summary>
/// <param name="token">RTF 토큰</param>
public RTFNode(RTFToken token)
{
this.keyword = token.Keyword;
this.hasParameter = token.HasParameter;
this.parameter = token.Parameter;
if(token.TokenType == RTFTokenType.Control)
{
this.nodeType = RTFNodeType.CONTROL;
}
else if(token.TokenType == RTFTokenType.Control)
{
this.nodeType = RTFNodeType.CONTROL;
}
else if(token.TokenType == RTFTokenType.Keyword)
{
this.nodeType = RTFNodeType.KEYWORD;
}
else if(token.TokenType == RTFTokenType.ExtendedKeyword)
{
this.nodeType = RTFNodeType.EXTERNAL_KEYWORD;
}
else if(token.TokenType == RTFTokenType.Text)
{
this.nodeType = RTFNodeType.TEXT;
}
else
{
this.nodeType = RTFNodeType.TEXT;
}
}
#endregion
#region 생성자 - RTFNode(nodeType, keyword)
/// <summary>
/// 생성자
/// </summary>
/// <param name="nodeType">노드 타입</param>
/// <param name="keyword">키워드</param>
public RTFNode(RTFNodeType nodeType, string keyword)
{
this.nodeType = nodeType;
this.keyword = keyword;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 쓰기 - Write(writer)
/// <summary>
/// 쓰기
/// </summary>
/// <param name="writer">RTF 라이터</param>
public virtual void Write(RTFWriter writer)
{
if(this.nodeType == RTFNodeType.CONTROL || this.nodeType == RTFNodeType.KEYWORD || this.nodeType == RTFNodeType.EXTERNAL_KEYWORD)
{
if(this.hasParameter)
{
writer.WriteKeyword(this.keyword + this.parameter, this.nodeType == RTFNodeType.EXTERNAL_KEYWORD);
}
else
{
writer.WriteKeyword(this.keyword, this.nodeType == RTFNodeType.EXTERNAL_KEYWORD);
}
}
else if(this.nodeType == RTFNodeType.TEXT)
{
writer.WriteText(this.keyword);
}
}
#endregion
}
}
▶ RTFNodeGroup.cs
using System;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF 노드 그룹
/// </summary>
public class RTFNodeGroup : RTFNode
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region Field
/// <summary>
/// 자식 노드 리스트
/// </summary>
protected RTFNodeList childNodeList = new RTFNodeList();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 자식 노드 리스트 - ChildNodeList
/// <summary>
/// 자식 노드 리스트
/// </summary>
public override RTFNodeList ChildNodeList
{
get
{
return this.childNodeList;
}
}
#endregion
#region 첫번째 노드 - FirstNode
/// <summary>
/// 첫번째 노드
/// </summary>
public RTFNode FirstNode
{
get
{
if(this.childNodeList.Count > 0)
{
return this.childNodeList[0];
}
else
{
return null;
}
}
}
#endregion
#region 키워드 - Keyword
/// <summary>
/// 키워드
/// </summary>
public override string Keyword
{
get
{
if(this.childNodeList.Count > 0)
{
return this.childNodeList[0].Keyword;
}
else
{
return null;
}
}
set
{
}
}
#endregion
#region 매개 변수 소유 여부 - HasParameter
/// <summary>
/// 매개 변수 소유 여부
/// </summary>
public override bool HasParameter
{
get
{
if(this.childNodeList.Count > 0)
{
return this.childNodeList[0].HasParameter;
}
else
{
return false;
}
}
set
{
}
}
#endregion
#region 매개 변수 - Parameter
/// <summary>
/// 매개 변수
/// </summary>
public override int Parameter
{
get
{
if(this.childNodeList.Count > 0)
{
return this.childNodeList[0].Parameter;
}
else
{
return 0;
}
}
}
#endregion
#region 텍스트 - Text
/// <summary>
/// 텍스트
/// </summary>
public virtual string Text
{
get
{
StringBuilder stringBuilder = new StringBuilder();
foreach(RTFNode childNode in this.childNodeList)
{
if(childNode is RTFNodeGroup)
{
stringBuilder.Append(((RTFNodeGroup)childNode).Text);
}
if(childNode.NodeType == RTFNodeType.TEXT)
{
stringBuilder.Append(childNode.Keyword);
}
}
return stringBuilder.ToString();
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFNodeGroup()
/// <summary>
/// 생성자
/// </summary>
public RTFNodeGroup()
{
this.nodeType = RTFNodeType.GROUP;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 자식 추가하기 - AppendChild(node)
/// <summary>
/// 자식 추가하기
/// </summary>
/// <param name="node">RTF 노드</param>
public void AppendChild(RTFNode node)
{
CheckChildNodeList();
if(node == null)
{
throw new ArgumentNullException("node");
}
if(node == this)
{
throw new ArgumentException("node != this");
}
node.Parent = this;
node.OwnerDocument = this.ownerDocument;
ChildNodeList.Add(node);
}
#endregion
#region 자식 삽입하기 - InsertChild(index, node)
/// <summary>
/// 자식 삽입하기
/// </summary>
/// <param name="index">인덱스</param>
/// <param name="node">RTF 노드</param>
public void InsertChild(int index, RTFNode node)
{
CheckChildNodeList();
if(node == null)
{
throw new ArgumentNullException("node");
}
if(node == this)
{
throw new ArgumentException("node != this");
}
node.Parent = this;
node.OwnerDocument = this.ownerDocument;
ChildNodeList.Insert(index, node);
}
#endregion
#region 자식 제거하기 - RemoveChild(node)
/// <summary>
/// 자식 제거하기
/// </summary>
/// <param name="node">RTF 노드</param>
public void RemoveChild(RTFNode node)
{
CheckChildNodeList();
if(node == null)
{
throw new ArgumentNullException("node");
}
if(node == this)
{
throw new ArgumentException("node != this");
}
ChildNodeList.Remove(node);
}
#endregion
#region 키 검색하기 - SearchKey(Keyword, searchChild)
/// <summary>
/// 키 검색하기
/// </summary>
/// <param name="Keyword">키워드</param>
/// <param name="searchChild">자식 검색 여부</param>
/// <returns>RTF 노드</returns>
public RTFNode SearchKey(string Keyword, bool searchChild)
{
foreach(RTFNode node in this.childNodeList)
{
if(node.NodeType == RTFNodeType.KEYWORD || node.NodeType == RTFNodeType.EXTERNAL_KEYWORD || node.NodeType == RTFNodeType.CONTROL)
{
if(node.Keyword == Keyword)
{
return node;
}
}
if(searchChild)
{
if(node is RTFNodeGroup)
{
RTFNodeGroup nodeGroup = (RTFNodeGroup)node;
RTFNode nodeFound = nodeGroup.SearchKey(Keyword, true);
if(nodeFound != null)
{
return nodeFound;
}
}
}
}
return null;
}
#endregion
#region 노드 리스트 구하기 - GetNodeList(includeGroupNode)
/// <summary>
/// 노드 리스트 구하기
/// </summary>
/// <param name="includeGroupNode">그룹 노드 포함 여부</param>
/// <returns>노드 리스트</returns>
public RTFNodeList GetNodeList(bool includeGroupNode)
{
RTFNodeList list = new RTFNodeList();
AddAllNodes(list, includeGroupNode);
return list ;
}
#endregion
#region 쓰기 - Write(writer)
/// <summary>
/// 쓰기
/// </summary>
/// <param name="writer">RTF 라이터</param>
public override void Write(RTFWriter writer)
{
writer.WriteStartGroup();
foreach(RTFNode childNode in this.childNodeList)
{
childNode.Write(writer);
}
writer.WriteEndGroup();
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region 텍스트 병합하기 - MergeText()
/// <summary>
/// 텍스트 병합하기
/// </summary>
internal void MergeText()
{
RTFNodeList list = new RTFNodeList();
StringBuilder stringBuilder = new StringBuilder();
ByteBuffer buffer = new ByteBuffer();
foreach(RTFNode childNode in this.childNodeList)
{
if(childNode.NodeType == RTFNodeType.TEXT)
{
AddString(stringBuilder, buffer);
stringBuilder.Append(childNode.Keyword);
continue ;
}
if(childNode.NodeType == RTFNodeType.CONTROL && childNode.Keyword == "\'" && childNode.HasParameter)
{
buffer.Add((byte)childNode.Parameter);
continue ;
}
else if(childNode.NodeType == RTFNodeType.CONTROL || childNode.NodeType == RTFNodeType.KEYWORD)
{
if(childNode.Keyword == "tab")
{
AddString(stringBuilder, buffer);
stringBuilder.Append('\t');
continue;
}
if(childNode.Keyword == "emdash")
{
AddString(stringBuilder, buffer);
stringBuilder.Append('j');
continue;
}
if(childNode.Keyword == string.Empty)
{
AddString(stringBuilder, buffer);
stringBuilder.Append('Ƀ');
continue;
}
}
AddString(stringBuilder, buffer);
if(stringBuilder.Length > 0)
{
list.Add(new RTFNode(RTFNodeType.TEXT, stringBuilder.ToString()));
stringBuilder = new StringBuilder();
}
list.Add(childNode);
}
AddString(stringBuilder, buffer);
if(stringBuilder.Length > 0)
{
list.Add(new RTFNode(RTFNodeType.TEXT, stringBuilder.ToString()));
}
this.childNodeList.Clear();
foreach(RTFNode node in list)
{
node.Parent = this;
node.OwnerDocument = this.ownerDocument;
this.childNodeList.Add(node);
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 모든 노드 추가하기 - AddAllNodes(targetNodeList, includeGroupNode)
/// <summary>
/// 모든 노드 추가하기
/// </summary>
/// <param name="targetNodeList">타겟 노드 리스트</param>
/// <param name="includeGroupNode">그룹 노드 포함 여부</param>
private void AddAllNodes(RTFNodeList targetNodeList, bool includeGroupNode)
{
foreach(RTFNode childNode in this.childNodeList)
{
if(childNode is RTFNodeGroup)
{
if(includeGroupNode)
{
targetNodeList.Add(childNode);
}
((RTFNodeGroup)childNode).AddAllNodes(targetNodeList, includeGroupNode);
}
else
{
targetNodeList.Add(childNode);
}
}
}
#endregion
#region 문자열 추가하기 - AddString(stringBuilder, buffer)
/// <summary>
/// 문자열 추가하기
/// </summary>
/// <param name="stringBuilder">문자열 빌더</param>
/// <param name="buffer">버퍼</param>
private void AddString(StringBuilder stringBuilder, ByteBuffer buffer)
{
if(buffer.Count > 0)
{
string text = buffer.GetString(this.ownerDocument.RuntimeEncoding);
stringBuilder.Append(text);
buffer.Reset();
}
}
#endregion
#region 자식 노드 리스트 체크하기 - CheckChildNodeList()
/// <summary>
/// 자식 노드 리스트 체크하기
/// </summary>
private void CheckChildNodeList()
{
if(ChildNodeList == null)
{
throw new Exception("child node is invalidate");
}
}
#endregion
}
}
▶ RTFNodeList.cs
using System;
using System.Collections;
using System.Diagnostics;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF 노드 리스트
/// </summary>
[DebuggerDisplay("Count={Count}")]
[DebuggerTypeProxy(typeof(RTFInstanceDebugView))]
public class RTFNodeList : CollectionBase
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱서 - this[index]
/// <summary>
/// 인덱서
/// </summary>
public RTFNode this[int index]
{
get
{
return (RTFNode)List[index];
}
}
#endregion
#region 인덱서 - this[keyword]
/// <summary>
/// 인덱서
/// </summary>
public RTFNode this[string Keyword]
{
get
{
foreach(RTFNode node in this)
{
if(node.Keyword == Keyword)
{
return node;
}
}
return null;
}
}
#endregion
#region 인덱서 - this[type]
/// <summary>
/// 인덱서
/// </summary>
public RTFNode this[Type type]
{
get
{
foreach(RTFNode node in this)
{
if(type.Equals(node.GetType()))
{
return node;
}
}
return null;
}
}
#endregion
#region 텍스트 - Text
/// <summary>
/// 텍스트
/// </summary>
public string Text
{
get
{
StringBuilder stringBuilder = new StringBuilder();
foreach(RTFNode node in this)
{
if(node.NodeType == RTFNodeType.TEXT)
{
stringBuilder.Append(node.Keyword);
}
else if(node is RTFNodeGroup)
{
string text = node.ChildNodeList.Text ;
if(text != null)
{
stringBuilder.Append(text);
}
}
}
return stringBuilder.ToString();
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 매개 변수 구하기 - GetParameter(key, defaultValue)
/// <summary>
/// 매개 변수 구하기
/// </summary>
/// <param name="key">키</param>
/// <param name="defaultValue">디폴트 값</param>
/// <returns>매개 변수</returns>
public int GetParameter(string key, int defaultValue)
{
foreach(RTFNode node in this)
{
if(node.Keyword == key && node.HasParameter)
{
return node.Parameter;
}
}
return defaultValue;
}
#endregion
#region 키 포함 여부 구하기 - ContainsKey(Key)
/// <summary>
/// 키 포함 여부 구하기
/// </summary>
/// <param name="Key">키</param>
/// <returns>키 포함 여부</returns>
public bool ContainsKey(string Key)
{
return this[Key] != null;
}
#endregion
#region 인덱스 구하기 - GetIndex(node)
/// <summary>
/// 인덱스 구하기
/// </summary>
/// <param name="node">RTF 노드</param>
/// <returns>인덱스</returns>
public int GetIndex(RTFNode node)
{
return List.IndexOf(node);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region 추가하기 - Add(node)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="node">노드</param>
internal void Add(RTFNode node)
{
List.Add(node);
}
#endregion
#region 삽입하기 - Insert(index , node)
/// <summary>
/// 삽입하기
/// </summary>
/// <param name="index">인덱스</param>
/// <param name="node">노드</param>
internal void Insert(int index , RTFNode node)
{
List.Insert(index, node);
}
#endregion
#region 범위 추가하기 - AddRange(nodeList)
/// <summary>
/// 범위 추가하기
/// </summary>
/// <param name="nodeList">노드 리스트</param>
internal void AddRange(RTFNodeList nodeList)
{
InnerList.AddRange(nodeList);
}
#endregion
#region 제거하기 - Remove(node)
/// <summary>
/// 제거하기
/// </summary>
/// <param name="node">노드</param>
internal void Remove(RTFNode node)
{
Remove(node);
}
#endregion
}
}
▶ RTFNodeType.cs
namespace TestLibrary
{
/// <summary>
/// RTF 노드 타입
/// </summary>
public enum RTFNodeType
{
/// <summary>
/// Root
/// </summary>
ROOT,
/// <summary>
/// Keyword
/// </summary>
KEYWORD,
/// <summary>
/// External Keyword
/// </summary>
EXTERNAL_KEYWORD,
/// <summary>
/// Control
/// </summary>
CONTROL,
/// <summary>
/// Text
/// </summary>
TEXT,
/// <summary>
/// Group
/// </summary>
GROUP,
/// <summary>
/// None
/// </summary>
NONE
}
}
▶ RTFObjectType.cs
namespace TestLibrary
{
/// <summary>
/// RTF 객체 타입
/// </summary>
public enum RTFObjectType
{
/// <summary>
/// EMB
/// </summary>
EMB,
/// <summary>
/// LINK
/// </summary>
LINK,
/// <summary>
/// AUTLINK
/// </summary>
AUTLINK ,
/// <summary>
/// SUB
/// </summary>
SUB,
/// <summary>
/// PUB
/// </summary>
PUB,
/// <summary>
/// ICEMB
/// </summary>
ICEMB,
/// <summary>
/// HTML
/// </summary>
HTML,
/// <summary>
/// OCX
/// </summary>
OCX
}
}
▶ RTFPictureType.cs
namespace TestLibrary
{
/// <summary>
/// RTF 그림 타입
/// </summary>
public enum RTFPictureType
{
/// <summary>
/// EMF
/// </summary>
EMF,
/// <summary>
/// PNG
/// </summary>
PNG,
/// <summary>
/// JPEG
/// </summary>
JPEG,
/// <summary>
/// PICT
/// </summary>
PICT,
/// <summary>
/// OS/2 METAFILE
/// </summary>
OS2METAFILE,
/// <summary>
/// WINDOWS METAFILE
/// </summary>
METAFILE,
/// <summary>
/// WINDOWS DIB
/// </summary>
DIB ,
/// <summary>
/// BITMAP
/// </summary>
BITMAP
}
}
▶ RTFRawDocument.cs
using System;
using System.Collections;
using System.Drawing;
using System.IO;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF 원시 문서
/// </summary>
public class RTFRawDocument : RTFNodeGroup
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region Field
/// <summary>
/// 문서 정보
/// </summary>
protected RTFDocumentInfo documentInfo = new RTFDocumentInfo();
/// <summary>
/// 색상 테이블
/// </summary>
protected RTFColorTable colorTable = new RTFColorTable();
/// <summary>
/// 폰트 테이블
/// </summary>
protected RTFFontTable fontTable = new RTFFontTable();
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 인코딩
/// </summary>
private Encoding encoding = null;
/// <summary>
/// 폰트 문자 세트 인코딩
/// </summary>
private Encoding fontChartSetEncoding = null;
/// <summary>
/// 연관 폰트 문자 세트 인코딩
/// </summary>
private Encoding associateFontChartSetEncoding = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문서 정보 - DocumentInfo
/// <summary>
/// 문서 정보
/// </summary>
public RTFDocumentInfo DocumentInfo
{
get
{
return this.documentInfo;
}
}
#endregion
#region 부모 - Parent
/// <summary>
/// 부모
/// </summary>
public override RTFNodeGroup Parent
{
get
{
return null;
}
set
{
}
}
#endregion
#region 소유자 문서 - OwnerDocument
/// <summary>
/// 소유자 문서
/// </summary>
public override RTFRawDocument OwnerDocument
{
get
{
return this;
}
set
{
}
}
#endregion
#region 색상 테이블 - ColorTable
/// <summary>
/// 색상 테이블
/// </summary>
public RTFColorTable ColorTable
{
get
{
return this.colorTable;
}
}
#endregion
#region 폰트 테이블 - FontTable
/// <summary>
/// 폰트 테이블
/// </summary>
public RTFFontTable FontTable
{
get
{
return this.fontTable;
}
}
#endregion
#region 인코딩 - Encoding
/// <summary>
/// 인코딩
/// </summary>
public Encoding Encoding
{
get
{
if(this.encoding == null)
{
RTFNode node = childNodeList[RTFConstant.ANSICPG];
if(node != null && node.HasParameter)
{
this.encoding = Encoding.GetEncoding(node.Parameter);
}
}
if(this.encoding == null)
{
this.encoding = Encoding.Default;
}
return this.encoding;
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Internal
#region 실행시 인코딩 - RuntimeEncoding
/// <summary>
/// 실행시 인코딩
/// </summary>
internal Encoding RuntimeEncoding
{
get
{
if(this.fontChartSetEncoding != null)
{
return this.fontChartSetEncoding;
}
if(this.associateFontChartSetEncoding != null)
{
return this.associateFontChartSetEncoding;
}
return this.Encoding;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFRawDocument()
/// <summary>
/// 생성자
/// </summary>
public RTFRawDocument()
{
this.ownerDocument = this;
this.parent = null;
this.colorTable.CheckValueExistWhenAdd = false;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 로드하기 - Load(reader)
/// <summary>
/// 로드하기
/// </summary>
/// <param name="reader">RTF 리더</param>
public void Load(RTFReader reader)
{
this.childNodeList.Clear();
Stack stack = new Stack();
RTFNodeGroup newNodeGroup = null;
RTFNode newNode = null;
while(reader.ReadToken() != null)
{
if(reader.CurrentTokenType == RTFTokenType.GroupStart)
{
if(newNodeGroup == null)
{
newNodeGroup = this;
}
else
{
newNodeGroup = new RTFNodeGroup();
newNodeGroup.OwnerDocument = this;
}
if(newNodeGroup != this)
{
RTFNodeGroup peekNodeGroup = (RTFNodeGroup)stack.Peek();
peekNodeGroup.AppendChild(newNodeGroup);
}
stack.Push(newNodeGroup);
}
else if(reader.CurrentTokenType == RTFTokenType.GroupEnd)
{
newNodeGroup = (RTFNodeGroup)stack.Pop();
newNodeGroup.MergeText();
if(newNodeGroup.FirstNode is RTFNode)
{
switch(newNodeGroup.Keyword)
{
case RTFConstant.FONTTBL :
ReadFontTable(newNodeGroup);
break;
case RTFConstant.COLORTBL :
ReadColorTable(newNodeGroup);
break;
case RTFConstant.INFO :
ReadDocumentInfo(newNodeGroup);
break;
}
}
if(stack.Count > 0)
{
newNodeGroup = (RTFNodeGroup)stack.Peek();
}
else
{
break;
}
}
else
{
newNode = new RTFNode(reader.CurrentToken);
newNode.OwnerDocument = this;
newNodeGroup.AppendChild(newNode);
if(newNode.Keyword == RTFConstant.F)
{
RTFFont font = this.FontTable[newNode.Parameter];
if(font != null)
{
this.fontChartSetEncoding = font.Encoding;
}
else
{
this.fontChartSetEncoding = null;
}
}
else if(newNode.Keyword == RTFConstant.AF)
{
RTFFont font = this.FontTable[newNode.Parameter];
if(font != null)
{
this.associateFontChartSetEncoding = font.Encoding;
}
else
{
this.associateFontChartSetEncoding = null;
}
}
}
}
while(stack.Count > 0)
{
newNodeGroup = (RTFNodeGroup)stack.Pop();
newNodeGroup.MergeText();
}
}
#endregion
#region 로드하기- Load(filePath)
/// <summary>
/// 로드하기
/// </summary>
/// <param name="filePath">파일 경로</param>
public void Load(string filePath)
{
this.encoding = null;
using(RTFReader reader = new RTFReader())
{
if(reader.LoadRTFFile(filePath))
{
Load(reader);
reader.Close();
}
reader.Close();
}
}
#endregion
#region 로드하기 - Load(textReader)
/// <summary>
/// 로드하기
/// </summary>
/// <param name="textReader">텍스트 리더</param>
public void Load(TextReader textReader)
{
RTFReader rtfReader = new RTFReader();
rtfReader.LoadReader(textReader);
Load(rtfReader);
}
#endregion
#region RTF 텍스트 로드하기 - LoadRTFText(rtf)
/// <summary>
/// RTF 텍스트 로드하기
/// </summary>
/// <param name="rtf">RTF</param>
public void LoadRTFText(string rtf)
{
this.encoding = null;
using(RTFReader reader = new RTFReader())
{
if(reader.LoadRTFText(rtf))
{
Load(reader);
reader.Close();
}
reader.Close();
}
}
#endregion
#region 쓰기 - Write(writer)
/// <summary>
/// 쓰기
/// </summary>
/// <param name="writer">RTF 라이터</param>
public override void Write(RTFWriter writer)
{
writer.Encoding = this.Encoding;
base.Write(writer);
}
#endregion
#region 저장하기 - Save(filePath)
/// <summary>
/// 저장하기
/// </summary>
/// <param name="filePath">파일 경로</param>
public void Save(string filePath)
{
using(RTFWriter writer = new RTFWriter(filePath))
{
Write(writer);
writer.Close();
}
}
#endregion
#region 저장하기 - Save(stream)
/// <summary>
/// 저장하기
/// </summary>
/// <param name="stream">스트림</param>
public void Save(Stream stream)
{
using(RTFWriter writer = new RTFWriter(new StreamWriter(stream , Encoding)))
{
Write(writer);
writer.Close();
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 폰트 테이블 읽기 - ReadFontTable(nodeGroup)
/// <summary>
/// 폰트 테이블 읽기
/// </summary>
/// <param name="nodeGroup">노드 그룹</param>
private void ReadFontTable(RTFNodeGroup nodeGroup)
{
this.fontTable.Clear();
foreach(RTFNode node in nodeGroup.ChildNodeList)
{
if(node is RTFNodeGroup)
{
int index = -1;
string name = null;
int characterSet = 0;
foreach(RTFNode item in node.ChildNodeList)
{
if(item.Keyword == "f" && item.HasParameter)
{
index = item.Parameter;
}
else if(item.Keyword == RTFConstant.FCHARSET)
{
characterSet = item.Parameter;
}
else if(item.NodeType == RTFNodeType.TEXT)
{
if(item.Keyword != null && item.Keyword.Length > 0)
{
name = item.Keyword;
break;
}
}
}
if(index >= 0 && name != null)
{
if(name.EndsWith(";"))
{
name = name.Substring(0, name.Length - 1);
}
name = name.Trim();
RTFFont font = new RTFFont(index, name);
font.CharacterSet = characterSet;
this.fontTable.Add(font);
}
}
}
}
#endregion
#region 색상 테이블 읽기 - ReadColorTable(nodeGroup)
/// <summary>
/// 색상 테이블 읽기
/// </summary>
/// <param name="nodeGroup">노드 그룹</param>
private void ReadColorTable(RTFNodeGroup nodeGroup)
{
this.colorTable.Clear();
int red = -1;
int green = -1;
int blue = -1;
foreach(RTFNode node in nodeGroup.ChildNodeList)
{
if(node.Keyword == "red")
{
red = node.Parameter;
}
else if(node.Keyword == "green")
{
green = node.Parameter;
}
else if(node.Keyword == "blue")
{
blue = node.Parameter;
}
if(node.Keyword == ";")
{
if(red >= 0 && green >= 0 && blue >= 0)
{
Color color = Color.FromArgb(255, red, green, blue);
this.colorTable.Add(color);
red = -1;
green = -1;
blue = -1;
}
}
}
if(red >= 0 && green >= 0 && blue >= 0)
{
Color color = Color.FromArgb(255, red, green, blue);
this.colorTable.Add(color);
}
}
#endregion
#region 문서 정보 읽기 - ReadDocumentInfo(nodeGroup)
/// <summary>
/// 문서 정보 읽기
/// </summary>
/// <param name="nodeGroup">노드 그룹</param>
private void ReadDocumentInfo(RTFNodeGroup nodeGroup)
{
this.documentInfo.Clear();
foreach(RTFNode node in nodeGroup.ChildNodeList)
{
if((node is RTFNodeGroup) == false)
{
continue;
}
if(node.Keyword == "creatim")
{
this.documentInfo.CreateTime = ReadDateTime(node);
}
else if(node.Keyword == "revtim")
{
this.documentInfo.UpdateTime = ReadDateTime(node);
}
else if(node.Keyword == "printim")
{
this.documentInfo.PrintTime = ReadDateTime(node);
}
else if(node.Keyword == "buptim")
{
this.documentInfo.BackupTime = ReadDateTime(node);
}
else
{
if(node.HasParameter)
{
this.documentInfo.SetInfo(node.Keyword, node.Parameter.ToString());
}
else
{
this.documentInfo.SetInfo(node.Keyword, node.ChildNodeList.Text);
}
}
}
}
#endregion
#region 날짜/시간 읽기 - ReadDateTime(node)
/// <summary>
/// 날짜/시간 읽기
/// </summary>
/// <param name="node">노드</param>
/// <returns>날짜/시간</returns>
private DateTime ReadDateTime(RTFNode node)
{
int year = node.ChildNodeList.GetParameter("yr" , 1900);
int month = node.ChildNodeList.GetParameter("mo" , 1 );
int day = node.ChildNodeList.GetParameter("dy" , 1 );
int hour = node.ChildNodeList.GetParameter("hr" , 0 );
int minute = node.ChildNodeList.GetParameter("min", 0 );
int second = node.ChildNodeList.GetParameter("sec", 0 );
return new DateTime(year, month, day, hour, minute, second);
}
#endregion
}
}
▶ RTFRawLayerInfo.cs
namespace TestLibrary
{
/// <summary>
/// RTF 원시 레이어 정보
/// </summary>
public class RTFRawLayerInfo
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// UC 값
/// </summary>
private int ucValue = 0;
/// <summary>
/// UC 값 카운트
/// </summary>
private int ucValueCount = 0;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region UC 값 - UCValue
/// <summary>
/// UC 값
/// </summary>
public int UCValue
{
get
{
return this.ucValue;
}
set
{
this.ucValue = value;
this.ucValueCount = 0;
}
}
#endregion
#region UC 값 카운트 - UCValueCount
/// <summary>
/// UC 값 카운트
/// </summary>
public int UCValueCount
{
get
{
return this.ucValueCount;
}
set
{
this.ucValueCount = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region UC 값 카운트 체크하기 - CheckUCValueCount()
/// <summary>
/// UC 값 카운트 체크하기
/// </summary>
/// <returns>UC 값 카운트 체크 결과</returns>
public bool CheckUCValueCount()
{
this.ucValueCount--;
return this.ucValueCount < 0;
}
#endregion
#region 복제하기 - Clone()
/// <summary>
/// 복제하기
/// </summary>
/// <returns>RTF 원시 레이어 정보</returns>
public RTFRawLayerInfo Clone()
{
return (RTFRawLayerInfo)MemberwiseClone();
}
#endregion
}
}
▶ RTFReader.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF 리더
/// </summary>
public class RTFReader : IDisposable
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 어휘 분석기
/// </summary>
private RTFLex lex = null;
/// <summary>
/// 내부 리더
/// </summary>
private TextReader innerReader = null;
/// <summary>
/// 베이스 스트림
/// </summary>
private Stream baseStream = null;
/// <summary>
/// 현재 토큰
/// </summary>
private RTFToken currentToken = null;
/// <summary>
/// 그룹 내 첫번째 토큰 여부
/// </summary>
private bool firstTokenInGroup = false;
/// <summary>
/// 마지막 토큰
/// </summary>
private RTFToken lastToken = null;
/// <summary>
/// 레벨
/// </summary>
private int level = 0;
/// <summary>
/// 토큰 카운트
/// </summary>
private int tokenCount = 0;
/// <summary>
/// 디폴트 프로세스 이용 가능 여부
/// </summary>
private bool enableDefaultProcess = true;
/// <summary>
/// 레이어 정보 스택
/// </summary>
private Stack<RTFRawLayerInfo> layerInfoStack = new Stack<RTFRawLayerInfo>();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 내부 리더 - InnerReader
/// <summary>
/// 내부 리더
/// </summary>
public TextReader InnerReader
{
get
{
return this.innerReader;
}
}
#endregion
#region 현재 토큰 - CurrentToken
/// <summary>
/// 현재 토큰
/// </summary>
public RTFToken CurrentToken
{
get
{
return this.currentToken;
}
}
#endregion
#region 현재 토큰 타입 - CurrentTokenType
/// <summary>
/// 현재 토큰 타입
/// </summary>
public RTFTokenType CurrentTokenType
{
get
{
if(this.currentToken == null)
{
return RTFTokenType.None;
}
else
{
return this.currentToken.TokenType;
}
}
}
#endregion
#region 현재 키워드 - CurrentKeyword
/// <summary>
/// 현재 키워드
/// </summary>
public string CurrentKeyword
{
get
{
if(this.currentToken == null)
{
return null;
}
else
{
return this.currentToken.Keyword;
}
}
}
#endregion
#region 현재 매개 변수 소유 여부 - HasCurrentParameter
/// <summary>
/// 현재 매개 변수 소유 여부
/// </summary>
public bool HasCurrentParameter
{
get
{
if(this.currentToken == null)
{
return false;
}
else
{
return this.currentToken.HasParameter;
}
}
}
#endregion
#region 현재 매개 변수 - CurrentParameter
/// <summary>
/// 현재 매개 변수
/// </summary>
public int CurrentParameter
{
get
{
if(this.currentToken == null)
{
return 0;
}
else
{
return this.currentToken.Parameter;
}
}
}
#endregion
#region 컨텐트 위치 - ContentPosition
/// <summary>
/// 컨텐트 위치
/// </summary>
public int ContentPosition
{
get
{
if(this.baseStream == null)
{
return 0;
}
else
{
return (int)this.baseStream.Position;
}
}
}
#endregion
#region 컨텐트 길이 - ContentLength
/// <summary>
/// 컨텐트 길이
/// </summary>
public int ContentLength
{
get
{
if(this.baseStream == null)
{
return 0;
}
else
{
return (int)this.baseStream.Length;
}
}
}
#endregion
#region 그룹 내 첫번째 토큰 여부 - FirstTokenInGroup
/// <summary>
/// 그룹 내 첫번째 토큰 여부
/// </summary>
public bool FirstTokenInGroup
{
get
{
return this.firstTokenInGroup;
}
}
#endregion
#region 마지막 토큰 - LastToken
/// <summary>
/// 마지막 토큰
/// </summary>
public RTFToken LastToken
{
get
{
return this.lastToken;
}
}
#endregion
#region 레벨 - Level
/// <summary>
/// 레벨
/// </summary>
public int Level
{
get
{
return this.level;
}
}
#endregion
#region 토큰 카운트 - TokenCount
/// <summary>
/// 토큰 카운트
/// </summary>
public int TokenCount
{
get
{
return this.tokenCount;
}
set
{
this.tokenCount = value;
}
}
#endregion
#region 디폴트 프로세스 이용 가능 여부 - EnableDefaultProcess
/// <summary>
/// 디폴트 프로세스 이용 가능 여부
/// </summary>
public bool EnableDefaultProcess
{
get
{
return this.enableDefaultProcess;
}
set
{
this.enableDefaultProcess = value;
}
}
#endregion
#region 현재 레이어 정보 - CurrentLayerInfo
/// <summary>
/// 현재 레이어 정보
/// </summary>
public RTFRawLayerInfo CurrentLayerInfo
{
get
{
if(this.layerInfoStack.Count == 0)
{
this.layerInfoStack.Push(new RTFRawLayerInfo());
}
return this.layerInfoStack.Peek();
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFReader()
/// <summary>
/// 생성자
/// </summary>
public RTFReader()
{
}
#endregion
#region 생성자 - RTFReader(filePath)
/// <summary>
/// 생성자
/// </summary>
/// <param name="filePath">파일 경로</param>
public RTFReader(string filePath)
{
LoadRTFFile(filePath);
}
#endregion
#region 생성자 - RTFReader(stream)
/// <summary>
/// 생성자
/// </summary>
/// <param name="stream">스트림</param>
public RTFReader(Stream stream)
{
StreamReader reader = new StreamReader(stream, Encoding.ASCII);
LoadReader(reader);
this.baseStream = stream;
}
#endregion
#region 생성자 - RTFReader(reader)
/// <summary>
/// 생성자
/// </summary>
/// <param name="reader">텍스트 리더</param>
public RTFReader(TextReader reader)
{
LoadReader(reader);
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region RTF 파일 로드하기 - LoadRTFFile(filePath)
/// <summary>
/// RTF 파일 로드하기
/// </summary>
/// <param name="filePath">파일 경로</param>
/// <returns>처리 결과</returns>
public bool LoadRTFFile(string filePath)
{
this.currentToken = null;
if(File.Exists(filePath))
{
FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
this.innerReader = new StreamReader(stream, Encoding.ASCII);
this.baseStream = stream;
this.lex = new RTFLex(this.innerReader);
return true;
}
return false;
}
#endregion
#region 리더 로드하기 - LoadReader(reader)
/// <summary>
/// 리더 로드하기
/// </summary>
/// <param name="reader">리더</param>
/// <returns>처리 결과</returns>
public bool LoadReader(TextReader reader)
{
this.currentToken = null;
if(reader != null)
{
this.innerReader = reader;
this.lex = new RTFLex(this.innerReader);
return true ;
}
return false;
}
#endregion
#region RTF 텍스트 로드하기 - LoadRTFText(rtf)
/// <summary>
/// RTF 텍스트 로드하기
/// </summary>
/// <param name="rtf">RTF</param>
/// <returns>처리 결과</returns>
public bool LoadRTFText(string rtf)
{
this.currentToken = null;
if(rtf != null && rtf.Length > 3)
{
this.innerReader = new StringReader(rtf);
this.lex = new RTFLex(this.innerReader);
return true;
}
return false;
}
#endregion
#region 토큰 타입 엿보기 - PeekTokenType()
/// <summary>
/// 토큰 타입 엿보기
/// </summary>
/// <returns>토큰 타입</returns>
public RTFTokenType PeekTokenType()
{
return this.lex.PeekTokenType();
}
#endregion
#region 디폴트 프로세스 처리하기 - DefaultProcess()
/// <summary>
/// 디폴트 프로세스 처리하기
/// </summary>
public void DefaultProcess()
{
if(CurrentToken != null)
{
switch(CurrentToken.Keyword)
{
case "uc" :
CurrentLayerInfo.UCValue = CurrentParameter;
break;
}
}
}
#endregion
#region 토큰 읽기 - ReadToken()
/// <summary>
/// 토큰 읽기
/// </summary>
/// <returns>토큰</returns>
public RTFToken ReadToken()
{
this.firstTokenInGroup = false;
this.lastToken = this.currentToken;
if(this.lastToken != null && this.lastToken.TokenType == RTFTokenType.GroupStart)
{
this.firstTokenInGroup = true;
}
this.currentToken = this.lex.ReadNextToken();
if(this.currentToken == null || this.currentToken.TokenType == RTFTokenType.EOF)
{
this.currentToken = null;
return null;
}
this.tokenCount++;
if(this.currentToken.TokenType == RTFTokenType.GroupStart)
{
if(this.layerInfoStack.Count == 0)
{
this.layerInfoStack.Push(new RTFRawLayerInfo());
}
else
{
RTFRawLayerInfo layerInfo = this.layerInfoStack.Peek();
this.layerInfoStack.Push(layerInfo.Clone());
}
this.level++;
}
else if(this.currentToken.TokenType == RTFTokenType.GroupEnd)
{
if(this.layerInfoStack.Count > 0)
{
this.layerInfoStack.Pop();
}
this.level--;
}
if(this.EnableDefaultProcess)
{
this.DefaultProcess();
}
return this.currentToken;
}
#endregion
#region 끝까지 읽기 - ReadToEndGround()
/// <summary>
/// 끝까지 읽기
/// </summary>
/// <remarks>
/// 현재 그룹이 끝날 때까지 데이터를 읽고 무시하고 끝을 유지한다.
/// </remarks>
public void ReadToEndGround()
{
int level = 0;
while(true)
{
int character = this.innerReader.Peek();
if(character == -1)
{
break;
}
else if(character == '{')
{
level++;
}
else if(character == '}')
{
level--;
if(level < 0)
{
break;
}
}
this.innerReader.Read();
}
}
#endregion
#region 닫기 - Close()
/// <summary>
/// 닫기
/// </summary>
public void Close()
{
if(this.innerReader != null)
{
this.innerReader.Close();
this.innerReader = null;
}
}
#endregion
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"RTFReader Level:{this.level} {CurrentKeyword}";
}
#endregion
#region 리소스 해제하기 - Dispose()
/// <summary>
/// 리소스 해제하기
/// </summary>
public void Dispose()
{
Close();
}
#endregion
}
}
▶ RTFTextAlignment.cs
namespace TestLibrary
{
/// <summary>
/// RTF 텍스트 정렬
/// </summary>
public enum RTFTextAlignment
{
/// <summary>
/// 왼쪽
/// </summary>
LEFT,
/// <summary>
/// 가운데
/// </summary>
CENTER,
/// <summary>
/// 오른쪽
/// </summary>
RIGHT,
/// <summary>
/// 양쪽 정렬
/// </summary>
JUSTIFY
}
}
▶ RTFTextContainer.cs
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF 텍스트 컨테이너
/// </summary>
internal class RTFTextContainer
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 문서
/// </summary>
private RTFDOMDocument document = null;
/// <summary>
/// 버퍼
/// </summary>
private ByteBuffer buffer = new ByteBuffer();
/// <summary>
/// 문자열 빌더
/// </summary>
private StringBuilder stringBuilder = new StringBuilder();
/// <summary>
/// 레벨
/// </summary>
private int level = 0;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문서 - Document
/// <summary>
/// 문서
/// </summary>
public RTFDOMDocument Document
{
get
{
return this.document;
}
set
{
this.document = value;
}
}
#endregion
#region 컨텐트 소유 여부 - HasContent
/// <summary>
/// 컨텐트 소유 여부
/// </summary>
public bool HasContent
{
get
{
CheckBuffer();
return this.stringBuilder.Length > 0;
}
}
#endregion
#region 텍스트 - Text
/// <summary>
/// 텍스트
/// </summary>
public string Text
{
get
{
CheckBuffer();
return this.stringBuilder.ToString();
}
}
#endregion
#region 레벨 - Level
/// <summary>
/// 레벨
/// </summary>
public int Level
{
get
{
return this.level;
}
set
{
this.level = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFTextContainer(document)
/// <summary>
/// 생성자
/// </summary>
/// <param name="document">문서</param>
public RTFTextContainer(RTFDOMDocument document)
{
this.document = document;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 추가하기 - Append(text)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="text">텍스트</param>
public void Append(string text)
{
if(string.IsNullOrEmpty(text) == false)
{
CheckBuffer();
this.stringBuilder.Append(text);
}
}
#endregion
#region 수락하기 - Accept(token, reader)
/// <summary>
/// 수락하기
/// </summary>
/// <param name="token">토큰</param>
/// <param name="reader">리더</param>
/// <returns>처리 결과</returns>
public bool Accept(RTFToken token, RTFReader reader)
{
if(token == null)
{
return false;
}
if(token.TokenType == RTFTokenType.Text)
{
if(reader != null)
{
if(token.Keyword[0] == '?')
{
if(reader.LastToken != null)
{
if(reader.LastToken.TokenType == RTFTokenType.Keyword && reader.LastToken.Keyword == "u" && reader.LastToken.HasParameter)
{
if(token.Keyword.Length > 0)
{
CheckBuffer();
}
return true;
}
}
}
}
CheckBuffer();
this.stringBuilder.Append(token.Keyword);
return true ;
}
else if(token.TokenType == RTFTokenType.Control && token.Keyword == "'" && token.HasParameter)
{
if(reader.CurrentLayerInfo.CheckUCValueCount())
{
this.buffer.Add((byte)token.Parameter);
}
return true;
}
if(token.Keyword == RTFConstant.U && token.HasParameter)
{
CheckBuffer();
this.stringBuilder.Append((char)token.Parameter);
reader.CurrentLayerInfo.UCValueCount = reader.CurrentLayerInfo.UCValue;
return true;
}
if(token.Keyword == "tab")
{
CheckBuffer();
this.stringBuilder.Append("\t");
return true;
}
if(token.Keyword == "emdash")
{
CheckBuffer();
this.stringBuilder.Append('—');
return true;
}
if(token.Keyword == "")
{
CheckBuffer();
this.stringBuilder.Append('-');
return true;
}
return false;
}
#endregion
#region 지우기 - Clear()
/// <summary>
/// 지우기
/// </summary>
public void Clear()
{
this.buffer.Clear();
this.stringBuilder = new StringBuilder();
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 버퍼 체크하기 - CheckBuffer()
/// <summary>
/// 버퍼 체크하기
/// </summary>
private void CheckBuffer()
{
if(this.buffer.Count > 0)
{
string text = this.buffer.GetString(this.document.RuntimeEncoding);
this.stringBuilder.Append(text);
this.buffer.Clear();
}
}
#endregion
}
}
▶ RTFToken.cs
namespace TestLibrary
{
/// <summary>
/// rtf token type
/// </summary>
public class RTFToken
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 토큰 타입
/// </summary>
private RTFTokenType tokenType = RTFTokenType.None;
/// <summary>
/// 키워드
/// </summary>
private string keyword = null;
/// <summary>
/// 부모
/// </summary>
private RTFToken parent = null;
/// <summary>
/// 매개 변수 소유 여부
/// </summary>
private bool hasParameter = false;
/// <summary>
/// 매개 변수
/// </summary>
private int parameter = 0;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 토큰 타입 - TokenType
/// <summary>
/// 토큰 타입
/// </summary>
public RTFTokenType TokenType
{
get
{
return this.tokenType;
}
set
{
this.tokenType = value;
}
}
#endregion
#region 키워드 - Keyword
/// <summary>
/// 키워드
/// </summary>
public string Keyword
{
get
{
return this.keyword;
}
set
{
this.keyword = value;
}
}
#endregion
#region 부모 - Parent
/// <summary>
/// 부모
/// </summary>
public RTFToken Parent
{
get
{
return this.parent;
}
set
{
this.parent = value;
}
}
#endregion
#region 매개 변수 소유 여부 - HasParameter
/// <summary>
/// 매개 변수 소유 여부
/// </summary>
public bool HasParameter
{
get
{
return this.hasParameter;
}
set
{
this.hasParameter = value;
}
}
#endregion
#region 매개 변수 - Parameter
/// <summary>
/// 매개 변수
/// </summary>
public int Parameter
{
get
{
return this.parameter;
}
set
{
this.parameter = value;
}
}
#endregion
#region 텍스트 토큰 여부 - IsTextToken
/// <summary>
/// 텍스트 토큰 여부
/// </summary>
public bool IsTextToken
{
get
{
if(this.tokenType == RTFTokenType.Text)
{
return true;
}
if(this.tokenType == RTFTokenType.Control && this.keyword == "'" && this.hasParameter)
{
return true;
}
return false;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
if(this.tokenType == RTFTokenType.Keyword)
{
return Keyword + Parameter;
}
else if(this.tokenType == RTFTokenType.GroupStart)
{
return "{";
}
else if(this.tokenType == RTFTokenType.GroupEnd)
{
return "}";
}
else if(this.tokenType == RTFTokenType.Text)
{
return "Text:" + Parameter;
}
return this.tokenType.ToString() + ":" + Keyword + " " + Parameter;
}
#endregion
}
}
▶ RTFTokenType.cs
namespace TestLibrary
{
/// <summary>
/// RTF 토큰 타입
/// </summary>
public enum RTFTokenType
{
/// <summary>
/// 해당 무
/// </summary>
None,
/// <summary>
/// 키워드
/// </summary>
Keyword,
/// <summary>
/// 확장 키워드
/// </summary>
ExtendedKeyword,
/// <summary>
/// 컨트롤
/// </summary>
Control,
/// <summary>
/// 텍스트
/// </summary>
Text,
/// <summary>
/// 파일 끝
/// </summary>
EOF,
/// <summary>
/// 그룹 시작
/// </summary>
GroupStart,
/// <summary>
/// 그룹 종료
/// </summary>
GroupEnd
}
}
▶ RTFUtility.cs
namespace TestLibrary
{
/// <summary>
/// RTF 유틸리티
/// </summary>
public static class RTFUtility
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 컨텐트 엘리먼트 소유 여부 구하기 - HasContentElement(rootElement)
/// <summary>
/// 컨텐트 엘리먼트 소유 여부 구하기
/// </summary>
/// <param name="rootElement">루트 엘리먼트</param>
/// <returns>컨텐트 엘리먼트 소유 여부</returns>
public static bool HasContentElement(RTFDOMElement rootElement)
{
if(rootElement.ElementList.Count == 0)
{
return false;
}
if(rootElement.ElementList.Count == 1)
{
if(rootElement.ElementList[0] is RTFDOMParagraph)
{
RTFDOMParagraph paragraph = (RTFDOMParagraph)rootElement.ElementList[0];
if(paragraph.ElementList.Count == 0)
{
return false;
}
}
}
return true;
}
#endregion
}
}
▶ RTFVerticalAlignment.cs
namespace TestLibrary
{
/// <summary>
/// RTF 수직 정렬
/// </summary>
public enum RTFVerticalAlignment
{
/// <summary>
/// 위쪽
/// </summary>
Top,
/// <summary>
/// 가운데
/// </summary>
Middle,
/// <summary>
/// 아래쪽
/// </summary>
Bottom
}
}
▶ RTFWriter.cs
using System;
using System.IO;
using System.Text;
namespace TestLibrary
{
/// <summary>
/// RTF 라이터
/// </summary>
public class RTFWriter : IDisposable
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 텍스트 라이터
/// </summary>
private TextWriter writer = null;
/// <summary>
/// 인코딩
/// </summary>
private Encoding encoding = Encoding.Default ;
/// <summary>
/// 들여쓰기 여부
/// </summary>
private bool indent = false;
/// <summary>
/// 들여쓰기 문자열
/// </summary>
private string indentString = " ";
/// <summary>
/// 그룹 레벨
/// </summary>
private int groupLevel = 0;
/// <summary>
/// 현재 위치
/// </summary>
private int currentPosition = 0 ;
/// <summary>
/// 현재 라인 헤드
/// </summary>
private int currentLineHead = 0 ;
/// <summary>
/// 16진수 문자열
/// </summary>
private const string HEXADECIMAL = "0123456789abcdef";
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인코딩 - Encoding
/// <summary>
/// 인코딩
/// </summary>
public Encoding Encoding
{
get
{
return this.encoding;
}
set
{
this.encoding = value;
}
}
#endregion
#region 들여쓰기 - Indent
/// <summary>
/// 들여쓰기
/// </summary>
public bool Indent
{
get
{
return this.indent;
}
set
{
this.indent = value;
}
}
#endregion
#region 들여쓰기 문자열 - IndentString
/// <summary>
/// 들여쓰기 문자열
/// </summary>
public string IndentString
{
get
{
return this.indentString;
}
set
{
this.indentString = value;
}
}
#endregion
#region 그룹 레벨 - GroupLevel
/// <summary>
/// 그룹 레벨
/// </summary>
public int GroupLevel
{
get
{
return this.groupLevel;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RTFWriter(writer)
/// <summary>
/// 생성자
/// </summary>
/// <param name="writer">텍스트 라이터</param>
public RTFWriter(TextWriter writer)
{
this.writer = writer;
}
#endregion
#region 생성자 - RTFWriter(filePath)
/// <summary>
/// 생성자
/// </summary>
/// <param name="filePath">파일 경로</param>
public RTFWriter(string filePath)
{
this.writer = new StreamWriter(filePath, false, Encoding.ASCII);
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 닫기 - Close()
/// <summary>
/// 닫기
/// </summary>
public void Close()
{
if(this.groupLevel > 0)
{
throw new Exception("Some group does not finish");
}
if(this.writer != null)
{
this.writer.Close();
this.writer = null;
}
}
#endregion
#region 버퍼 비우기 - Flush()
/// <summary>
/// 버퍼 비우기
/// </summary>
public void Flush()
{
if(this.writer != null)
{
this.writer.Flush();
}
}
#endregion
#region 그룹 쓰기 - WriteGroup(keyword)
/// <summary>
/// 그룹 쓰기
/// </summary>
/// <param name="keyword">키워드</param>
public void WriteGroup(string keyword)
{
this.WriteStartGroup();
this.WriteKeyword(keyword);
this.WriteEndGroup();
}
#endregion
#region 그룹 시작 쓰기 - WriteStartGroup()
/// <summary>
/// 그룹 시작 쓰기
/// </summary>
public void WriteStartGroup()
{
if(this.indent)
{
WriteNewLineInternal();
this.writer.Write("{");
}
else
{
this.writer.Write("{");
}
this.groupLevel++;
}
#endregion
#region 그룹 종료 쓰기 - WriteEndGroup()
/// <summary>
/// 그룹 종료 쓰기
/// </summary>
public void WriteEndGroup()
{
this.groupLevel--;
if(this.groupLevel < 0)
{
throw new Exception("group level error");
}
if(this.indent)
{
WriteNewLineInternal();
WriteInternal("}");
}
else
{
WriteInternal("}");
}
}
#endregion
#region 원시 쓰기 - WriteRaw(text)
/// <summary>
/// 원시 쓰기
/// </summary>
/// <param name="text">텍스트</param>
public void WriteRaw(string text)
{
if(text != null && text.Length > 0)
{
WriteInternal(text);
}
}
#endregion
#region 키워드 쓰기 - WriteKeyword(keyword , externKeyword)
/// <summary>
/// 키워드 쓰기
/// </summary>
/// <param name="keyword">키워드</param>
/// <param name="externKeyword">외부 키워드 여부</param>
public void WriteKeyword(string keyword , bool externKeyword)
{
if(keyword == null || keyword.Length == 0)
{
throw new ArgumentNullException("keyword");
}
if(this.indent == false && (keyword == "par" || keyword == "pard"))
{
WriteInternal(Environment.NewLine);
}
if(this.indent)
{
if(keyword == "par" || keyword == "pard")
{
WriteNewLineInternal();
}
}
if(externKeyword)
{
WriteInternal("\\*\\");
}
else
{
WriteInternal("\\");
}
WriteInternal(keyword);
}
#endregion
#region 키워드 쓰기 - WriteKeyword(keyword)
/// <summary>
/// 키워드 쓰기
/// </summary>
/// <param name="keyword">키워드</param>
public void WriteKeyword(string keyword)
{
WriteKeyword(keyword, false);
}
#endregion
#region 텍스트 쓰기 - WriteText(text , addWhitespace)
/// <summary>
/// 텍스트 쓰기
/// </summary>
/// <param name="text">텍스트</param>
/// <param name="addWhitespace">공백 문자 추가 여부</param>
public void WriteText(string text , bool addWhitespace)
{
if(text == null || text.Length == 0)
{
return;
}
if(addWhitespace)
{
WriteInternal(' ');
}
for(int i = 0; i < text.Length; i ++)
{
char character = text[i];
WriteCharacterInternal(character);
}
}
#endregion
#region 텍스트 쓰기 - WriteText(text)
/// <summary>
/// 텍스트 쓰기
/// </summary>
/// <param name="text">텍스트</param>
public void WriteText(string text)
{
if(text == null || text.Length == 0)
{
return ;
}
WriteText(text , true);
}
#endregion
#region 유니코드 텍스트 쓰기 - WriteUnicodeText(text)
/// <summary>
/// 유니코드 텍스트 쓰기
/// </summary>
/// <param name="text">텍스트</param>
public void WriteUnicodeText(string text)
{
if(string.IsNullOrEmpty(text) == false)
{
WriteKeyword("uc1");
foreach(char character in text)
{
if(character > 127)
{
int value1 = (int)character;
short value2 = (short)value1;
WriteKeyword("u" + value2.ToString());
WriteRaw(" ?");
}
else
{
WriteCharacterInternal(character);
}
}
}
}
#endregion
#region 바이트 쓰기 - WriteByte(value)
/// <summary>
/// 바이트 쓰기
/// </summary>
/// <param name="value">값</param>
public void WriteByte(byte value)
{
int high = (value & 0xf0) >> 4;
int low = value & 0xf;
this.writer.Write(HEXADECIMAL[high]);
this.writer.Write(HEXADECIMAL[low ]);
this.currentPosition += 2 ;
}
#endregion
#region 바이트 배열 쓰기 - WriteByteArray(byteArray)
/// <summary>
/// 바이트 배열 쓰기
/// </summary>
/// <param name="byteArray">바이트 배열</param>
public void WriteByteArray(byte[] byteArray)
{
if(byteArray == null || byteArray.Length == 0)
{
return;
}
WriteRaw(" ");
for(int i = 0; i < byteArray.Length; i++)
{
if((i % 32) == 0)
{
WriteRaw(Environment.NewLine);
WriteInternal();
}
else if((i % 8) == 0)
{
WriteRaw(" ");
}
byte value = byteArray[i];
int high = (value & 0xf0) >> 4;
int low = value & 0xf;
this.writer.Write(HEXADECIMAL[high]);
this.writer.Write(HEXADECIMAL[low ]);
this.currentPosition += 2;
}
}
#endregion
#region 리소스 해제하기 - Dispose()
/// <summary>
/// 리소스 해제하기
/// </summary>
public void Dispose()
{
Close();
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 문자 쓰기 (내부용) - WriteCharacterInternal(character)
/// <summary>
/// 문자 쓰기 (내부용)
/// </summary>
/// <param name="character">문자</param>
private void WriteCharacterInternal(char character)
{
if(character == '\t')
{
WriteKeyword("tab");
WriteInternal(' ');
}
if(character > 32 && character < 127)
{
if(character == '\\' || character == '{' || character == '}')
{
WriteInternal('\\');
}
WriteInternal(character);
}
else
{
byte[] byteArray = this.encoding.GetBytes(character.ToString());
for(int i = 0; i < byteArray.Length; i++)
{
WriteInternal("\\\'");
WriteByte(byteArray[i]);
}
}
}
#endregion
#region 쓰기 (내부용) - WriteInternal(character)
/// <summary>
/// 쓰기 (내부용)
/// </summary>
/// <param name="character">문자</param>
private void WriteInternal(char character)
{
this.currentPosition++;
this.writer.Write(character);
}
#endregion
#region 쓰기 (내부용) - WriteInternal(text)
/// <summary>
/// 쓰기 (내부용)
/// </summary>
/// <param name="text">텍스트</param>
private void WriteInternal(string text)
{
this.currentPosition += text.Length;
this.writer.Write(text);
}
#endregion
#region 쓰기 (내부용) - WriteInternal()
/// <summary>
/// 쓰기 (내부용)
/// </summary>
private void WriteInternal()
{
if(this.indent)
{
for(int i = 0; i < this.groupLevel; i++)
{
WriteInternal(this.indentString);
}
}
}
#endregion
#region 새 라인 쓰기 (내부용) - WriteNewLineInternal()
/// <summary>
/// 새 라인 쓰기 (내부용)
/// </summary>
private void WriteNewLineInternal()
{
if(this.indent)
{
if(this.currentPosition > 0)
{
WriteInternal(Environment.NewLine);
this.currentLineHead = this.currentPosition;
WriteInternal();
}
}
}
#endregion
}
}
▶ StringAttribute.cs
using System;
using System.ComponentModel;
namespace TestLibrary
{
/// <summary>
/// 문자열 특성
/// </summary>
[Serializable]
public class StringAttribute
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 명칭
/// </summary>
private string name = null;
/// <summary>
/// 값
/// </summary>
private string value = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 명칭 - Name
/// <summary>
/// 명칭
/// </summary>
[DefaultValue( null )]
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
#endregion
#region 값 - Value
/// <summary>
/// 값
/// </summary>
[DefaultValue( null)]
public string Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - StringAttribute()
/// <summary>
/// 생성자
/// </summary>
public StringAttribute()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return $"this.name={this.value}";
}
#endregion
}
}
▶ StringAttributeCollection.cs
using System;
using System.Collections;
using System.Diagnostics;
namespace TestLibrary
{
/// <summary>
/// 문자열 특성 컬렉션
/// </summary>
[Serializable]
[DebuggerTypeProxy(typeof(RTFInstanceDebugView))]
public class StringAttributeCollection : CollectionBase
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱서 - this[name]
/// <summary>
/// 인덱서
/// </summary>
/// <param name="name">명칭</param>
/// <returns>값</returns>
public string this[string name]
{
get
{
foreach(StringAttribute attribute in this)
{
if(attribute.Name == name)
{
return attribute.Value;
}
}
return null;
}
set
{
foreach(StringAttribute attribute in this)
{
if(attribute.Name == name)
{
if(value == null)
{
List.Remove(attribute);
}
else
{
attribute.Value = value;
}
return;
}
}
if(value != null)
{
StringAttribute newAttribute = new StringAttribute();
newAttribute.Name = name;
newAttribute.Value = value;
List.Add(newAttribute);
}
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - StringAttributeCollection()
/// <summary>
/// 생성자
/// </summary>
public StringAttributeCollection()
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 추가하기 - Add(item)
/// <summary>
/// 추가하기
/// </summary>
/// <param name="item">항목</param>
/// <returns>인덱스</returns>
public int Add(StringAttribute item)
{
return List.Add(item);
}
#endregion
#region 제거하기 - Remove(item)
/// <summary>
/// 제거하기
/// </summary>
/// <param name="item">항목</param>
public void Remove(StringAttribute item)
{
List.Remove(item);
}
#endregion
}
}
[TestProject 프로젝트]
▶ MainForm.cs
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using TestLibrary;
namespace TestProject
{
/// <summary>
/// 메인 폼
/// </summary>
public partial class MainForm : Form
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
this.loadRTFFileToolStripButton1.Click += loadRTFFileToolStripButton1_Click;
this.pasteFromClipboardToolStripButton.Click += pasteFromClipboardToolStripButton_Click;
this.loadRTFFileToolStripButton2.Click += loadRTFFileToolStripButton2_Click;
this.copyTextFormatToolStripButton.Click += copyTextFormatToolStripButton_Click;
this.copyRTFFormatToolStripButton.Click += copyRTFFormatToolStripButton_Click;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region RTF DOM 문서 진행시 처리하기 - document_Progress(sender, e)
/// <summary>
/// RTF DOM 문서 진행시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void document_Progress(object sender, ProgressEventArgs e)
{
this.toolStripProgressBar.Maximum = e.MaximumValue;
this.toolStripProgressBar.Value = e.Value;
}
#endregion
#region RTF 파일 로드 툴 스트립 버튼 1 클릭시 처리하기 - loadRTFFileToolStripButton1_Click(sender, e)
/// <summary>
/// RTF 파일 로드 툴 스트립 버튼 1 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void loadRTFFileToolStripButton1_Click(object sender, EventArgs e)
{
using(OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.CheckFileExists = true;
openFileDialog.Filter = "*.RTF|*.rtf";
if(openFileDialog.ShowDialog(this) == DialogResult.OK)
{
Update();
RTFDOMDocument document = new RTFDOMDocument();
document.Progress += document_Progress;
document.Load(openFileDialog.FileName);
this.textBox1.Text = document.GetDOMString();
Text = openFileDialog.FileName;
this.toolStripProgressBar.Value = 0;
}
}
}
#endregion
#region 클립보드에서 붙여넣기 툴 스트립 버튼 클릭시 처리하기 - pasteFromClipboardToolStripButton_Click(sender, e)
/// <summary>
/// 클립보드에서 붙여넣기 툴 스트립 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pasteFromClipboardToolStripButton_Click(object sender, EventArgs e)
{
IDataObject dataObject = Clipboard.GetDataObject();
if(dataObject.GetDataPresent(DataFormats.Rtf))
{
string rtf = dataObject.GetData(DataFormats.Rtf) as string;
RTFDOMDocument document = new RTFDOMDocument();
document.Progress += document_Progress;
document.LoadRTFText(rtf);
this.textBox1.Text = document.GetDOMString();
Text = string.Empty;
this.toolStripProgressBar.Value = 0;
}
}
#endregion
#region RTF 파일 로드 툴 스트립 버튼 2 클릭시 처리하기 - loadRTFFileToolStripButton2_Click(sender, e)
/// <summary>
/// RTF 파일 로드 툴 스트립 버튼 2 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void loadRTFFileToolStripButton2_Click(object sender, EventArgs e)
{
using(OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.CheckFileExists = true;
openFileDialog.Filter = "*.RTF|*.rtf";
if(openFileDialog.ShowDialog(this) == DialogResult.OK)
{
using(StreamReader reader = new StreamReader(openFileDialog.FileName, Encoding.ASCII))
{
this.textBox2.Text = reader.ReadToEnd();
Text = openFileDialog.FileName;
}
}
}
}
#endregion
#region 텍스트 서식으로 복사 툴 스트립 버튼 클릭시 처리하기 - copyTextFormatToolStripButton_Click(sender, e)
/// <summary>
/// 텍스트 서식으로 복사 툴 스트립 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void copyTextFormatToolStripButton_Click(object sender, EventArgs e)
{
Clipboard.SetData(DataFormats.Text, this.textBox2.Text);
}
#endregion
#region RTF 서식으로 복사 툴 스트립 버튼 클릭시 처리하기 - copyRTFFormatToolStripButton_Click(sender, e)
/// <summary>
/// RTF 서식으로 복사 툴 스트립 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void copyRTFFormatToolStripButton_Click(object sender, EventArgs e)
{
Clipboard.SetData(DataFormats.Rtf, this.textBox2.Text);
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
댓글을 달아 주세요