첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

■ RTF 파서를 사용해 RTF 문서 구조를 파싱하는 방법을 보여준다.

TestSolution.zip
0.10MB

[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("&lsquo;");           break;
                            case "rquote"    : stringBuilder.Append("&rsquo;");           break;
                            case "ldblquote" : stringBuilder.Append("&ldquo;");           break;
                            case "rdblquote" : stringBuilder.Append("&rdquo;");           break;
                            case "bullet"    : stringBuilder.Append("&bull;" );           break;
                            case "endash"    : stringBuilder.Append("&ndash;");           break;
                            case "emdash"    : stringBuilder.Append("&mdash;");           break;
                            case "~"         : stringBuilder.Append("&nbsp;" );           break;
                            case "_"         : stringBuilder.Append("&shy;"  );           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
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요