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