1 // =================================
 2 // Copyright (c) 2024 Seppo Laakko
 3 // Distributed under the MIT license
 4 // =================================
 5 
 6 using System;
 7 
 8 namespace System.Xml
 9 {
10     public abstract class CharacterData : Node
11     {
12         public CharacterData(NodeKind kind_const System.Lex.Span& span_int fileIndex_const string& name_) : this(kind_span_fileIndex_name_string())
13         {
14         }
15         public CharacterData(NodeKind kind_const System.Lex.Span& span_int fileIndex_const string& name_const string& data_) : 
16             base(kind_span_fileIndex_name_)data(data_)
17         {
18         }
19         [nodiscard]
20         public override Result<bool> Write(System.Text.CodeFormatter& formatter)
21         {
22             if (formatter.Error())
23             {
24                 return Result<bool>(ErrorId(formatter.GetErrorId()));
25             }
26             auto escapeValue = XmlCharDataEscape(data);
27             if (escapeValue.Error())
28             {
29                 return Result<bool>(ErrorId(escapeValue.GetErrorId()));
30             }
31             formatter << escapeValue.Value();
32             return Result<bool>(true);
33         }
34         public override bool ValueContainsNewLine() const
35         {
36             return data.Find('\n') != -1;
37         }
38         public const string& Data() const
39         {
40             return data;
41         }
42         private string data;
43     }
44 
45     [nodiscard]
46     public Result<string> XmlCharDataEscape(const string& text)
47     {
48         string result;
49         auto utf32Result = ToUtf32(text);
50         if (utf32Result.Error())
51         {
52             return Result<string>(ErrorId(utf32Result.GetErrorId()));
53         }
54         ustring value = utf32Result.Value();
55         for (uchar c : value)
56         {
57             switch (c)
58             {
59                 case '<':
60                 {
61                     result.Append("&lt;");
62                     break;
63                 }
64                 case '&':
65                 {
66                     result.Append("&amp;");
67                     break;
68                 }
69                 case '\r': case '\n':
70                 {
71                     result.Append(cast<char>(c));
72                     break;
73                 }
74                 default:
75                 {
76                     if (cast<int>(c) >= 32 && cast<int>(c) < 127)
77                     {
78                         result.Append(cast<char>(c));
79                     }
80                     else
81                     {
82                         int codePoint = cast<int>(c);
83                         string charText = "&#";
84                         charText.Append(ToString(codePoint)).Append(';');
85                         result.Append(charText);
86                     }
87                     break;
88                 }
89             }
90         }
91         return Result<string>(result);
92     }
93 }