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_tag_name_get PORTABLE C */
36 /* 6.1 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function isolates a tag name from the XML script. */
44 /* */
45 /* Note: the buffer size of tag_name, variable_name, variable_string */
46 /* and xml_parameter must be equal to or greater than */
47 /* UX_PICTBRIDGE_MAX_TAG_SIZE, UX_PICTBRIDGE_MAX_VARIABLE_SIZE, */
48 /* UX_PICTBRIDGE_MAX_STRING_SIZE and UX_PICTBRIDGE_MAX_STRING_SIZE. */
49 /* */
50 /* INPUT */
51 /* */
52 /* input_buffer Pointer to object buffer */
53 /* input_length Length of the object */
54 /* tag_name Where to store the tag */
55 /* variable_name Variable name */
56 /* variable_string Variable string */
57 /* xml_parameter ML parameter */
58 /* output_buffer Pointer after the tag */
59 /* output_length Length of the object */
60 /* tag_flag flag specific to this tag */
61 /* */
62 /* OUTPUT */
63 /* */
64 /* Completion Status */
65 /* */
66 /* CALLS */
67 /* */
68 /* */
69 /* CALLED BY */
70 /* */
71 /* _ux_pictbridge_object_parse */
72 /* */
73 /* RELEASE HISTORY */
74 /* */
75 /* DATE NAME DESCRIPTION */
76 /* */
77 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
78 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
79 /* verified memset and memcpy */
80 /* cases, */
81 /* resulting in version 6.1 */
82 /* */
83 /**************************************************************************/
_ux_pictbridge_tag_name_get(UCHAR * input_buffer,ULONG input_length,UCHAR * tag_name,UCHAR * variable_name,UCHAR * variable_string,UCHAR * xml_parameter,UCHAR ** output_buffer,ULONG * output_length,ULONG * tag_flag)84 UINT _ux_pictbridge_tag_name_get(UCHAR *input_buffer, ULONG input_length,
85 UCHAR *tag_name,
86 UCHAR *variable_name,
87 UCHAR *variable_string,
88 UCHAR *xml_parameter,
89 UCHAR **output_buffer, ULONG *output_length,
90 ULONG *tag_flag)
91 {
92 ULONG flag;
93 ULONG char_count;
94 UCHAR *tag_name_end;
95 UCHAR *variable_name_end;
96 UCHAR *variable_string_end;
97 UCHAR *xml_parameter_end;
98
99 /* Reset the local flags. */
100 flag = 0;
101
102 /* Reset the caller's tag_flag. */
103 *tag_flag = 0;
104
105 /* Char count reset. */
106 char_count = 0;
107
108 /* Reset the tag name buffer. */
109 _ux_utility_memory_set(tag_name, 0, UX_PICTBRIDGE_MAX_TAG_SIZE); /* Use case of memset is verified. */
110 tag_name_end = tag_name + UX_PICTBRIDGE_MAX_TAG_SIZE - 1;
111
112 /* Reset the variable name buffer. */
113 _ux_utility_memory_set(variable_name, 0, UX_PICTBRIDGE_MAX_VARIABLE_SIZE); /* Use case of memset is verified. */
114 variable_name_end = variable_name + UX_PICTBRIDGE_MAX_VARIABLE_SIZE - 1;
115
116 /* Reset the variable string buffer. */
117 _ux_utility_memory_set(variable_string, 0, UX_PICTBRIDGE_MAX_STRING_SIZE); /* Use case of memset is verified. */
118 variable_string_end = variable_string + UX_PICTBRIDGE_MAX_STRING_SIZE - 1;
119
120 /* Reset the xml parameter. */
121 _ux_utility_memory_set(xml_parameter, 0, UX_PICTBRIDGE_MAX_STRING_SIZE); /* Use case of memset is verified. */
122 xml_parameter_end = xml_parameter + UX_PICTBRIDGE_MAX_STRING_SIZE - 1;
123
124 /* We parse the current xml tag line. We are now positioned at the "<". */
125 while(input_length)
126 {
127 /* Get a character from the tag line. */
128 switch (*input_buffer)
129 {
130
131 case UX_PICTBRIDGE_TAG_CHAR_START_BRACKET :
132
133 /* Check to see if we are within a quote. */
134 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_STRING)
135 {
136
137 /* Yes, store the bracket in the string. */
138 if (variable_string > variable_string_end)
139 return(UX_BUFFER_OVERFLOW);
140 *variable_string++ = *input_buffer;
141
142 break;
143 }
144
145 /* Check to see if we are already in the bracket. */
146 if (flag & UX_PICTBRIDGE_TAG_FLAG_BEGIN)
147
148 /* Yes, we have a syntax violation. */
149 return(UX_PICTBRIDGE_ERROR_PARAMETER_MISSING);
150
151 else
152 /* Set the tag flag to start bracket. State machine is now in Tag. */
153 flag |= (UX_PICTBRIDGE_TAG_FLAG_BEGIN | UX_PICTBRIDGE_TAG_FLAG_IN_TAG);
154
155
156 break;
157
158
159 case UX_PICTBRIDGE_TAG_CHAR_CR :
160 case UX_PICTBRIDGE_TAG_CHAR_LF :
161
162 /* If we are in the middle of a <>, we have a format violation. If not, we may have an empty line. */
163 if (flag & UX_PICTBRIDGE_TAG_FLAG_BEGIN)
164
165 /* We have a XML tag violation. */
166 return(UX_PICTBRIDGE_ERROR_PARAMETER_MISSING);
167 else
168 break;
169
170 case UX_PICTBRIDGE_TAG_CHAR_SPACE :
171
172 /* If we are within a tag already, this masks the end. If not, continue looking for
173 an open bracket. */
174 if ((flag & UX_PICTBRIDGE_TAG_FLAG_BEGIN) == 0)
175 break;
176
177 /* Check to see if we are within a quote. */
178 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_STRING)
179 {
180 /* Yes, store the character. */
181 if (variable_string > variable_string_end)
182 return(UX_BUFFER_OVERFLOW);
183 *variable_string++ = UX_PICTBRIDGE_TAG_CHAR_SPACE;
184
185 break;
186 }
187
188 /* If we are in the flag state machine. It marks the end of the flag and maybe the
189 beginning of a variable. */
190 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_TAG)
191 {
192
193 /* get out of tag state machine. */
194 flag &= (ULONG)~UX_PICTBRIDGE_TAG_FLAG_IN_TAG;
195
196 /* Change state machine to variable. */
197 flag |= (ULONG)UX_PICTBRIDGE_TAG_FLAG_IN_VARIABLE;
198
199 }
200 break;
201
202 case UX_PICTBRIDGE_TAG_CHAR_EQUAL :
203
204 /* If we are not within a bracket, this is a loose character ! */
205 if ((flag & UX_PICTBRIDGE_TAG_FLAG_BEGIN) == 0)
206 break;
207
208 /* Check to see if we are within a string. */
209 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_STRING)
210 {
211 /* Yes, store the character. */
212 if (variable_string > variable_string_end)
213 return(UX_BUFFER_OVERFLOW);
214 *variable_string++ = *input_buffer;
215
216 break;
217 }
218
219 /* If we are in the flag state machine we have an error. */
220 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_TAG)
221
222 /* Error, we should have been in the variable state machine. */
223 return(UX_PICTBRIDGE_ERROR_PARAMETER_MISSING);
224
225 /* If we are in the variable state machine, change the state to expecting string. */
226 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_VARIABLE)
227 {
228
229 /* Get out of the variable state machine. */
230 flag &= (ULONG)~UX_PICTBRIDGE_TAG_FLAG_IN_VARIABLE;
231
232 /* Change state machine to expecting string. */
233 flag |= UX_PICTBRIDGE_TAG_FLAG_EXPECTING_STRING;
234
235 }
236 break;
237
238 case UX_PICTBRIDGE_TAG_CHAR_QUOTE :
239
240 /* Are we in the string state machine ? */
241 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_STRING)
242
243 /* Get out of the in string state machine. We are out of any state now. */
244 flag &= (ULONG)~UX_PICTBRIDGE_TAG_FLAG_IN_STRING;
245
246 else
247 {
248
249 /* Are we expecting a string ? */
250 if (flag & UX_PICTBRIDGE_TAG_FLAG_EXPECTING_STRING)
251 {
252
253 /* Get out of the expecting string state machine. */
254 flag &= (ULONG)~UX_PICTBRIDGE_TAG_FLAG_EXPECTING_STRING;
255
256 /* Change state machine to in string. */
257 flag |= UX_PICTBRIDGE_TAG_FLAG_IN_STRING;
258
259 }
260
261 else
262
263 /* Loose character ! */
264 return(UX_PICTBRIDGE_ERROR_PARAMETER_MISSING);
265
266 }
267
268 break;
269
270 case UX_PICTBRIDGE_TAG_CHAR_SLASH :
271
272 /* If we are in no particular state at the moment, we could have a begin slash or end slash. */
273 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_STRING)
274 {
275
276 /* We are in the variable string state machine. Store the "/" as a normal character. */
277 if (variable_string > variable_string_end)
278 return(UX_BUFFER_OVERFLOW);
279 *variable_string++ = *input_buffer;
280
281 break;
282 }
283 /* Check other states. */
284 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_TAG)
285 {
286
287 /* We are in a tag. 2 scenario here. We are either at the beginning or at the end. */
288 if (char_count != 0)
289
290 /* We are at the end of the tag, this is a self closing tag. */
291 *tag_flag |= UX_PICTBRIDGE_TAG_FLAG_SELF_CLOSING;
292
293 else
294
295 /* This is a normal closing tag. */
296 *tag_flag |= UX_PICTBRIDGE_TAG_FLAG_CLOSING;
297
298 /* We are done here. */
299 break;
300 }
301
302 else
303 {
304
305 /* If we are out of any state machine, it must be a self closing tag. */
306 if (flag & (UX_PICTBRIDGE_TAG_FLAG_IN_VARIABLE | UX_PICTBRIDGE_TAG_FLAG_EXPECTING_STRING))
307
308 /* This is a syntax error, abort. */
309 return(UX_PICTBRIDGE_ERROR_PARAMETER_MISSING);
310
311 else
312 {
313 /* We are at the end of the tag, this is a self closing tag. */
314 *tag_flag |= UX_PICTBRIDGE_TAG_FLAG_SELF_CLOSING;
315
316 /* We are done here. */
317 break;
318 }
319
320 }
321
322
323 case UX_PICTBRIDGE_TAG_CHAR_QUESTION_MARK :
324
325 /* If we are in no particular state at the moment, we could have a begin ? or end ?. */
326 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_STRING)
327
328 /* We are within a quoted string, do not proceed. */
329 break;
330
331 else
332
333 /* This is a comment line, no need for a closing tag. */
334 *tag_flag |= UX_PICTBRIDGE_TAG_FLAG_COMMENT;
335
336 break;
337
338 case UX_PICTBRIDGE_TAG_CHAR_END_BRACKET :
339
340 /* If we are in no particular state at the moment, we could have a begin ? or end ?. */
341 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_STRING)
342 {
343
344 /* Yes, store the bracket in the string. */
345 if (variable_string > variable_string_end)
346 return(UX_BUFFER_OVERFLOW);
347 *variable_string++ = *input_buffer;
348
349 break;
350 }
351
352 /* Check if we are within a bracket. */
353 if (flag & UX_PICTBRIDGE_TAG_FLAG_BEGIN)
354 {
355
356 /* Skip the closing bracket. */
357 input_buffer++;
358
359 /* Update length. */
360 input_length--;
361
362 /* We may have a xml parameter between the current tag and its closing counterpart. */
363 while(input_length)
364 {
365
366 /* Get a character between the tag brackets. */
367 switch (*input_buffer)
368 {
369
370 case UX_PICTBRIDGE_TAG_CHAR_CR :
371 case UX_PICTBRIDGE_TAG_CHAR_LF :
372
373 /* Skip potential CR/LF. */
374 break;
375
376
377 case UX_PICTBRIDGE_TAG_CHAR_START_BRACKET :
378
379 /* We have found the beginning of the next tag.
380 Set the output buffer position to the next "<". */
381 *output_buffer = input_buffer;
382
383 /* Set the length remaining. */
384 *output_length = input_length;
385
386 /* We are done here. */
387 return(UX_SUCCESS);
388
389 default :
390
391 /* Whatever we have now, we store into the XML parameter. */
392 if (xml_parameter > xml_parameter_end)
393 return(UX_BUFFER_OVERFLOW);
394 *xml_parameter++ = *input_buffer;
395 break;
396
397 }
398
399 /* Next position. */
400 input_buffer++;
401
402 /* Update length. */
403 input_length--;
404
405 }
406
407 /* Set the output buffer position. */
408 *output_buffer = input_buffer;
409
410 /* Set the length remaining. */
411 *output_length = input_length;
412
413 /* We have reached the end of the xml object. */
414 return(UX_SUCCESS);
415
416 }
417 else
418
419 /* We have a syntax error. */
420 return(UX_PICTBRIDGE_ERROR_SCRIPT_SYNTAX_ERROR);
421
422 default :
423
424 /* Check if we are within a bracket. */
425 if (flag & UX_PICTBRIDGE_TAG_FLAG_BEGIN)
426
427 /* Yes, increase the char count. This will tell us
428 if we are at the beginning of a tag or at the end. */
429 char_count++;
430
431 /* We have a regular character. Store it in the current state machine. */
432 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_TAG)
433 {
434 /* We are in the tag state machine. */
435 if (tag_name > tag_name_end)
436 return(UX_BUFFER_OVERFLOW);
437 *tag_name++ = *input_buffer;
438 }
439
440 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_VARIABLE)
441 {
442 /* We are in the variable state machine. */
443 if (variable_name > variable_name_end)
444 return(UX_BUFFER_OVERFLOW);
445 *variable_name++ = *input_buffer;
446 }
447
448 if (flag & UX_PICTBRIDGE_TAG_FLAG_IN_STRING)
449 {
450 /* We are in the variable string state machine. */
451 if (variable_string > variable_string_end)
452 return(UX_BUFFER_OVERFLOW);
453 *variable_string++ = *input_buffer;
454 }
455
456 break;
457
458 }
459
460 /* Next position. */
461 input_buffer++;
462
463 /* Update length. */
464 input_length--;
465
466 }
467
468 /* We get here when we reached an unexpected end of the XML object.
469 if we had a begin bracket, there is an unexpected end. If not, we
470 have an empty line. */
471 if (flag & UX_PICTBRIDGE_TAG_FLAG_BEGIN)
472
473 /* We have an error. */
474 return(UX_PICTBRIDGE_ERROR_PARAMETER_MISSING);
475
476 else
477
478 /* Not really an error, but we need to inform the caller there is no tag to process. */
479 return(UX_PICTBRIDGE_ERROR_EMPTY_LINE);
480
481 }
482
483