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