[NUI] Add license, delete unnecessary code (#2679)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / MarkupExpressionParser.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 //
19 // MarkupExpressionParser.cs
20 //
21 // This code is partly salvaged from moonlight. Following licence apply.
22 //
23 //
24 // Author(s):
25 //   Moonlight List (moonlight-list@lists.ximian.com)
26 //   Stephane Delcroix (stephane@mi8.be)
27 //
28 // Copyright 2009 Novell, Inc.
29 // Copyright 2013 Xamarin, Inc.
30 //
31 // Permission is hereby granted, free of charge, to any person obtaining
32 // a copy of this software and associated documentation files (the
33 // "Software"), to deal in the Software without restriction, including
34 // without limitation the rights to use, copy, modify, merge, publish,
35 // distribute, sublicense, and/or sell copies of the Software, and to
36 // permit persons to whom the Software is furnished to do so, subject to
37 // the following conditions:
38 // 
39 // The above copyright notice and this permission notice shall be
40 // included in all copies or substantial portions of the Software.
41 // 
42 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
45 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
46 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
47 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
48 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
49 //
50
51 using System;
52 using System.Text;
53
54 namespace Tizen.NUI.Xaml
55 {
56     internal abstract class MarkupExpressionParser
57     {
58         public object ParseExpression(ref string expression, IServiceProvider serviceProvider)
59         {
60             if (serviceProvider == null)
61                 throw new ArgumentNullException(nameof(serviceProvider));
62             if (expression.StartsWith("{}", StringComparison.Ordinal))
63                 return expression.Substring(2);
64
65             if (expression[expression.Length - 1] != '}')
66                 throw new Exception("Expression must end with '}'");
67
68             int len;
69             string match;
70             if (!MatchMarkup(out match, expression, out len))
71                 return false;
72             expression = expression.Substring(len).TrimStart();
73             if (expression.Length == 0)
74                 throw new Exception("Expression did not end in '}'");
75
76             var parser = Activator.CreateInstance(GetType()) as IExpressionParser;
77             return parser?.Parse(match, ref expression, serviceProvider);
78         }
79
80         internal static bool MatchMarkup(out string match, string expression, out int end)
81         {
82             if (expression.Length < 2)
83             {
84                 end = 1;
85                 match = null;
86                 return false;
87             }
88
89             if (expression[0] != '{')
90             {
91                 end = 2;
92                 match = null;
93                 return false;
94             }
95
96             int i;
97             bool found = false;
98             for (i = 1; i < expression.Length; i++)
99             {
100                 if (expression[i] == ' ')
101                     continue;
102                 found = true;
103                 break;
104             }
105
106             if (!found)
107             {
108                 end = 3;
109                 match = null;
110                 return false;
111             }
112
113             int c;
114             for (c = 0; c + i < expression.Length; c++)
115             {
116                 if (expression[i + c] == ' ' || expression[i + c] == '}')
117                     break;
118             }
119
120             if (i + c == expression.Length)
121             {
122                 end = 6;
123                 match = null;
124                 return false;
125             }
126
127             end = i + c;
128             match = expression.Substring(i, c);
129             return true;
130         }
131
132         protected void HandleProperty(string prop, IServiceProvider serviceProvider, ref string remaining, bool isImplicit)
133         {
134             char next;
135             object value = null;
136             string str_value;
137
138             if (isImplicit)
139             {
140                 SetPropertyValue(null, prop, null, serviceProvider);
141                 return;
142             }
143             remaining = remaining.TrimStart();
144             if (remaining.StartsWith("{", StringComparison.Ordinal))
145             {
146                 value = ParseExpression(ref remaining, serviceProvider);
147                 remaining = remaining.TrimStart();
148
149                 if (remaining.Length > 0 && remaining[0] == ',')
150                     remaining = remaining.Substring(1);
151                 else if (remaining.Length > 0 && remaining[0] == '}')
152                     remaining = remaining.Substring(1);
153
154                 str_value = value as string;
155             }
156             else
157                 str_value = GetNextPiece(ref remaining, out next);
158
159             SetPropertyValue(prop, str_value, value, serviceProvider);
160         }
161
162         protected abstract void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider);
163
164         protected string GetNextPiece(ref string remaining, out char next)
165         {
166             bool inString = false;
167             int end = 0;
168             char stringTerminator = '\0';
169             remaining = remaining.TrimStart();
170             if (remaining.Length == 0)
171             {
172                 next = Char.MaxValue;
173                 return null;
174             }
175
176             var piece = new StringBuilder();
177             // If we're inside a quoted string we append all chars to our piece until we hit the ending quote.
178             while (end < remaining.Length &&
179                    (inString || (remaining[end] != '}' && remaining[end] != ',' && remaining[end] != '=')))
180             {
181                 if (inString)
182                 {
183                     if (remaining[end] == stringTerminator)
184                     {
185                         inString = false;
186                         end++;
187                         break;
188                     }
189                 }
190                 else
191                 {
192                     if (remaining[end] == '\'' || remaining[end] == '"')
193                     {
194                         inString = true;
195                         stringTerminator = remaining[end];
196                         end++;
197                         continue;
198                     }
199                 }
200
201                 // If this is an escape char, consume it and append the next char to our piece.
202                 if (remaining[end] == '\\')
203                 {
204                     end++;
205                     if (end == remaining.Length)
206                         break;
207                 }
208                 piece.Append(remaining[end]);
209                 end++;
210             }
211
212             if (inString && end == remaining.Length)
213                 throw new Exception("Unterminated quoted string");
214
215             if (end == remaining.Length && !remaining.EndsWith("}", StringComparison.Ordinal))
216                 throw new Exception("Expression did not end with '}'");
217
218             if (end == 0)
219             {
220                 next = Char.MaxValue;
221                 return null;
222             }
223
224             next = remaining[end];
225             remaining = remaining.Substring(end + 1);
226
227             // Whitespace is trimmed from the end of the piece before stripping
228             // quote chars from the start/end of the string. 
229             while (piece.Length > 0 && char.IsWhiteSpace(piece[piece.Length - 1]))
230                 piece.Length--;
231
232             if (piece.Length >= 2)
233             {
234                 char first = piece[0];
235                 char last = piece[piece.Length - 1];
236                 if ((first == '\'' && last == '\'') || (first == '"' && last == '"'))
237                 {
238                     piece.Remove(piece.Length - 1, 1);
239                     piece.Remove(0, 1);
240                 }
241             }
242
243             return piece.ToString();
244         }
245     }
246 }