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