1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** USBX Component                                                        */
16 /**                                                                       */
17 /**   Pictbridge Application                                              */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 
23 /* Include necessary system files.  */
24 
25 #define UX_SOURCE_CODE
26 
27 #include "ux_api.h"
28 #include "ux_pictbridge.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _ux_pictbridge_object_parse                         PORTABLE C      */
36 /*                                                           6.3.0        */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function parses a XML based pictbridge object.                 */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    pictbridge                             Pictbridge instance          */
48 /*    xml_object_buffer                      Pointer to object buffer     */
49 /*    xml_object_length                      Length of the object         */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    Completion Status                                                   */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*                                                                        */
58 /*  CALLED BY                                                             */
59 /*                                                                        */
60 /*    _ux_pictbridge_object_get                                           */
61 /*                                                                        */
62 /*  RELEASE HISTORY                                                       */
63 /*                                                                        */
64 /*    DATE              NAME                      DESCRIPTION             */
65 /*                                                                        */
66 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
67 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
68 /*                                            resulting in version 6.1    */
69 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
70 /*                                            checked tag nesting depth,  */
71 /*                                            resulting in version 6.3.0  */
72 /*                                                                        */
73 /**************************************************************************/
_ux_pictbridge_object_parse(UX_PICTBRIDGE * pictbridge,UCHAR * xml_object_buffer,ULONG xml_object_length)74 UINT  _ux_pictbridge_object_parse(UX_PICTBRIDGE *pictbridge, UCHAR *xml_object_buffer,
75                                     ULONG xml_object_length)
76 {
77 UX_PICTBRIDGE_XML_ITEM                  *tag_item;
78 UX_PICTBRIDGE_XML_ITEM                  *tag_entry =  UX_NULL;
79 UCHAR                                   tag_name[UX_PICTBRIDGE_MAX_TAG_SIZE];
80 UCHAR                                   variable_name[UX_PICTBRIDGE_MAX_VARIABLE_SIZE];
81 UCHAR                                   variable_string[UX_PICTBRIDGE_MAX_STRING_SIZE];
82 UCHAR                                   xml_parameter[UX_PICTBRIDGE_MAX_STRING_SIZE];
83 UX_PICTBRIDGE_XML_ITEM                  *tag_history[UX_PICTBRIDGE_MAX_TAG_DEPTH];
84 ULONG                                   tag_history_index;
85 ULONG                                   tag_flag;
86 ULONG                                   closing_tag_count;
87 UINT                                    tag_name_length;
88 UINT                                    tag_history_length;
89 UINT                                    status;
90 
91     /* Set the tag position at root.  */
92     tag_item = _ux_pictbridge_xml_item_root;
93 
94     /* Clear the input tags.  */
95     pictbridge -> ux_pictbridge_input_tags =  0;
96 
97     /* Clear the input request.  */
98     pictbridge -> ux_pictbridge_input_request =  0;
99 
100     /* Tag history index is at root.  */
101     tag_history_index =  0;
102 
103     /* Closing tag count is reset.  */
104     closing_tag_count = 0;
105 
106     /* This variable remains untouched if the XML object's length is 0.  */
107     status =  UX_SUCCESS;
108 
109     /* We parse the object until all items are parsed or there is a syntax error
110        or a short object.  */
111     while(xml_object_length)
112     {
113 
114         /* Scan the object buffer for a tag.  */
115         status = _ux_pictbridge_tag_name_get(xml_object_buffer, xml_object_length, tag_name,
116                                         variable_name, variable_string, xml_parameter,
117                                         &xml_object_buffer, &xml_object_length, &tag_flag);
118 
119         /* We may have an error.  Check if this is an empty line in which case we are done. */
120         if (status != UX_SUCCESS)
121         {
122 
123             /* Check for empty line.  */
124             if (status == UX_PICTBRIDGE_ERROR_EMPTY_LINE)
125 
126                 /* Yes, we have an empty line. Do not proceed but we have a successful completion. */
127                 status = UX_SUCCESS;
128 
129             /* Do not proceed.  */
130             break;
131         }
132 
133         /* Check if this is a closing tag ? */
134         if (tag_flag & UX_PICTBRIDGE_TAG_FLAG_CLOSING)
135         {
136 
137             /* Assume the worst.  */
138             status = UX_PICTBRIDGE_ERROR_SCRIPT_SYNTAX_ERROR;
139 
140             /* Ensure we do not have a closing tag without a prior normal tag entry.  */
141             if (tag_history_index == 0)
142 
143                 /* Syntax error.  */
144                 break;
145 
146             /* One step back in the tag history.  */
147             tag_history_index--;
148 
149             /* Calculate the length of the tag item.  */
150             status = _ux_utility_string_length_check(tag_name, &tag_name_length, UX_PICTBRIDGE_MAX_TAG_SIZE);
151             if (status != UX_SUCCESS)
152 
153                 /* Bad name, we should never here if _tag_name_get is OK.  */
154                 break;
155 
156             /* Calculate the length of the current tag name in the tag history.  */
157             status = _ux_utility_string_length_check(tag_history[tag_history_index] -> ux_pictbridge_xml_item_tag_name, &tag_history_length, UX_PICTBRIDGE_MAX_TAG_SIZE);
158             if (status != UX_SUCCESS)
159 
160                 /* Bad name, we should never here if _tag_name_get is OK.  */
161                 return(status);
162 
163             /* If both length do not match, no need to check for a match.  */
164             if (tag_history_length == tag_name_length)
165             {
166 
167                 /* Both length match, we may have a tag match. Check the names */
168                 if (_ux_utility_memory_compare(tag_name, tag_history[tag_history_index] -> ux_pictbridge_xml_item_tag_name,
169                                         tag_name_length) != UX_SUCCESS)
170 
171                     /* Syntax error.  */
172                     break;
173             }
174             else
175 
176                 /* Syntax error.  */
177                 break;
178 
179             /* Increment the closing tag count. */
180             closing_tag_count++;
181 
182             /* If we have more than one closing tag consecutively, look for the parent.  */
183             if (closing_tag_count > 1)
184             {
185 
186                 /* Get the parent for this item and set it as the current tag_item.  We may already be at the root.  */
187                 if (tag_entry -> ux_pictbridge_xml_item_parent != UX_NULL)
188 
189                     /* We have a parent, set it.  */
190                     tag_item =  tag_entry -> ux_pictbridge_xml_item_parent;
191             }
192 
193             /* We set status to success.  */
194             status = UX_SUCCESS;
195 
196         }
197         else
198         {
199 
200             /* The tag name is in the tag_name variable but has not been verified yet.  */
201             status = _ux_pictbridge_tag_name_scan(tag_item, tag_name, &tag_entry);
202 
203             /* We may have an error.  */
204             if (status != UX_SUCCESS)
205 
206                 /* Do not proceed.  */
207                 break;
208 
209             /* Check if this is a comment tag ? */
210             if ((tag_flag & UX_PICTBRIDGE_TAG_FLAG_COMMENT) == 0)
211             {
212 
213                 /* Reset the closing tag count.  */
214                 closing_tag_count =  0;
215 
216                 /* Check if the tag history depth is fine for saving.  */
217                 if (tag_history_index >= UX_PICTBRIDGE_MAX_TAG_DEPTH)
218                 {
219 
220                     /* Syntax error.  */
221                     status = UX_BUFFER_OVERFLOW;
222 
223                     /* Do not proceed.  */
224                     break;
225                 }
226 
227                 /* Save the current tag in the tag history.  */
228                 tag_history[tag_history_index] = tag_entry;
229 
230                 /* Increase the current tag index.  */
231                 tag_history_index++;
232 
233                 /* Check if there is a main tag specified in the tag entry. */
234                 if (tag_entry -> ux_pictbridge_xml_item_tag_code != 0)
235                 {
236 
237                     /* If this is a leaf, the tag is not a main request but a variable to be returned.  */
238                     if (tag_entry -> ux_pictbridge_xml_item_child == UX_PICTBRIDGE_XML_LEAF)
239 
240                         /* This is a variable. Add it to the other ones.  */
241                         pictbridge -> ux_pictbridge_input_tags |=  tag_entry -> ux_pictbridge_xml_item_tag_code;
242 
243                     else
244 
245                         /* Yes we have a tag code, memorize it.  This is a main input request. */
246                         pictbridge -> ux_pictbridge_input_request =  tag_entry -> ux_pictbridge_xml_item_tag_code;
247                 }
248                 /* We may have a function associated with this tag. Do a sanity check.  */
249                 if (tag_entry -> ux_pictbridge_xml_item_function != UX_NULL)
250                 {
251                     /* There is a function associated, so call it.  */
252                     status = tag_entry -> ux_pictbridge_xml_item_function(pictbridge, variable_name, variable_string, xml_parameter);
253 
254                     /* We may have an error.  */
255                     if (status != UX_SUCCESS)
256 
257                        /* Do not proceed.  */
258                         break;
259                 }
260 
261                 /* Check if the tag has a child attached to it.
262                    If there is neither a child or a function, it means we do not treat this tag name. */
263                 if (tag_entry -> ux_pictbridge_xml_item_child != UX_NULL && tag_entry -> ux_pictbridge_xml_item_child != UX_PICTBRIDGE_XML_LEAF)
264                 {
265 
266                     /* We have a child, set it.  */
267                     tag_item =  tag_entry -> ux_pictbridge_xml_item_child;
268 
269                     /* Reset the tag codes.  */
270                     pictbridge -> ux_pictbridge_input_tags =  0;
271                 }
272 
273                 /* Check if this is a self closing tag ? */
274                 if (tag_flag & UX_PICTBRIDGE_TAG_FLAG_SELF_CLOSING)
275                 {
276 
277                     /* Assume the worst.  */
278                     status = UX_PICTBRIDGE_ERROR_SCRIPT_SYNTAX_ERROR;
279 
280                     /* Ensure we do not have a closing tag without a prior normal tag entry.  */
281                     if (tag_history_index == 0)
282 
283                         /* Syntax error.  */
284                         break;
285 
286                     /* One step back in the tag history.  */
287                     tag_history_index--;
288 
289                     /* Calculate the length of the tag item.   */
290                     status = _ux_utility_string_length_check(tag_name, &tag_name_length, UX_PICTBRIDGE_MAX_TAG_SIZE);
291                     if (status != UX_SUCCESS)
292 
293                         /* Bad name, we should never here if _tag_name_scan is OK!  */
294                         break;
295 
296                     /* Calculate the length of the current tag name in the tag history.  */
297                     status = _ux_utility_string_length_check(tag_history[tag_history_index] -> ux_pictbridge_xml_item_tag_name, &tag_history_length, UX_PICTBRIDGE_MAX_TAG_SIZE);
298                     if (status != UX_SUCCESS)
299 
300                         /* Bad name, we should never here if _tag_name_scan is OK!  */
301                         break;
302 
303                     /* If both length do not match, no need to check for a match.  */
304                     if (tag_history_length == tag_name_length)
305                     {
306 
307                         /* Both length match, we may have a tag match. Check the names */
308                         if (_ux_utility_memory_compare(tag_name, tag_history[tag_history_index] -> ux_pictbridge_xml_item_tag_name,
309                                             tag_name_length) != UX_SUCCESS)
310 
311                             /* Syntax error.  */
312                             break;
313                     }
314                     else
315 
316                         /* Syntax error.  */
317                         break;
318 
319                     /* Increment the closing tag count. */
320                     closing_tag_count++;
321 
322                     /* We set status to success.  */
323                     status = UX_SUCCESS;
324 
325                 }
326             }
327         }
328     }
329 
330     /* Return completion status.  */
331     return(status);
332 }
333