1 /** @file
2   Print Library internal worker functions.
3 
4   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "PrintLibInternal.h"
10 
11 #define WARNING_STATUS_NUMBER         5
12 #define ERROR_STATUS_NUMBER           33
13 
14 //
15 // Safe print checks
16 //
17 #define RSIZE_MAX             (PcdGet32 (PcdMaximumUnicodeStringLength))
18 #define ASCII_RSIZE_MAX       (PcdGet32 (PcdMaximumAsciiStringLength))
19 
20 #define SAFE_PRINT_CONSTRAINT_CHECK(Expression, RetVal)  \
21   do { \
22     ASSERT (Expression); \
23     if (!(Expression)) { \
24       return RetVal; \
25     } \
26   } while (FALSE)
27 
28 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
29 
30 //
31 // Longest string: RETURN_WARN_BUFFER_TOO_SMALL => 24 characters plus NUL byte
32 //
33 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mWarningString[][24+1] = {
34   "Success",                      //  RETURN_SUCCESS                = 0
35   "Warning Unknown Glyph",        //  RETURN_WARN_UNKNOWN_GLYPH     = 1
36   "Warning Delete Failure",       //  RETURN_WARN_DELETE_FAILURE    = 2
37   "Warning Write Failure",        //  RETURN_WARN_WRITE_FAILURE     = 3
38   "Warning Buffer Too Small",     //  RETURN_WARN_BUFFER_TOO_SMALL  = 4
39   "Warning Stale Data",           //  RETURN_WARN_STALE_DATA        = 5
40 };
41 
42 //
43 // Longest string: RETURN_INCOMPATIBLE_VERSION => 20 characters plus NUL byte
44 //
45 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mErrorString[][20+1] = {
46   "Load Error",                   //  RETURN_LOAD_ERROR             = 1  | MAX_BIT
47   "Invalid Parameter",            //  RETURN_INVALID_PARAMETER      = 2  | MAX_BIT
48   "Unsupported",                  //  RETURN_UNSUPPORTED            = 3  | MAX_BIT
49   "Bad Buffer Size",              //  RETURN_BAD_BUFFER_SIZE        = 4  | MAX_BIT
50   "Buffer Too Small",             //  RETURN_BUFFER_TOO_SMALL,      = 5  | MAX_BIT
51   "Not Ready",                    //  RETURN_NOT_READY              = 6  | MAX_BIT
52   "Device Error",                 //  RETURN_DEVICE_ERROR           = 7  | MAX_BIT
53   "Write Protected",              //  RETURN_WRITE_PROTECTED        = 8  | MAX_BIT
54   "Out of Resources",             //  RETURN_OUT_OF_RESOURCES       = 9  | MAX_BIT
55   "Volume Corrupt",               //  RETURN_VOLUME_CORRUPTED       = 10 | MAX_BIT
56   "Volume Full",                  //  RETURN_VOLUME_FULL            = 11 | MAX_BIT
57   "No Media",                     //  RETURN_NO_MEDIA               = 12 | MAX_BIT
58   "Media changed",                //  RETURN_MEDIA_CHANGED          = 13 | MAX_BIT
59   "Not Found",                    //  RETURN_NOT_FOUND              = 14 | MAX_BIT
60   "Access Denied",                //  RETURN_ACCESS_DENIED          = 15 | MAX_BIT
61   "No Response",                  //  RETURN_NO_RESPONSE            = 16 | MAX_BIT
62   "No mapping",                   //  RETURN_NO_MAPPING             = 17 | MAX_BIT
63   "Time out",                     //  RETURN_TIMEOUT                = 18 | MAX_BIT
64   "Not started",                  //  RETURN_NOT_STARTED            = 19 | MAX_BIT
65   "Already started",              //  RETURN_ALREADY_STARTED        = 20 | MAX_BIT
66   "Aborted",                      //  RETURN_ABORTED                = 21 | MAX_BIT
67   "ICMP Error",                   //  RETURN_ICMP_ERROR             = 22 | MAX_BIT
68   "TFTP Error",                   //  RETURN_TFTP_ERROR             = 23 | MAX_BIT
69   "Protocol Error",               //  RETURN_PROTOCOL_ERROR         = 24 | MAX_BIT
70   "Incompatible Version",         //  RETURN_INCOMPATIBLE_VERSION   = 25 | MAX_BIT
71   "Security Violation",           //  RETURN_SECURITY_VIOLATION     = 26 | MAX_BIT
72   "CRC Error",                    //  RETURN_CRC_ERROR              = 27 | MAX_BIT
73   "End of Media",                 //  RETURN_END_OF_MEDIA           = 28 | MAX_BIT
74   "Reserved (29)",                //  RESERVED                      = 29 | MAX_BIT
75   "Reserved (30)",                //  RESERVED                      = 30 | MAX_BIT
76   "End of File",                  //  RETURN_END_OF_FILE            = 31 | MAX_BIT
77   "Invalid Language",             //  RETURN_INVALID_LANGUAGE       = 32 | MAX_BIT
78   "Compromised Data"              //  RETURN_COMPROMISED_DATA       = 33 | MAX_BIT
79 };
80 
81 
82 /**
83   Internal function that places the character into the Buffer.
84 
85   Internal function that places ASCII or Unicode character into the Buffer.
86 
87   @param  Buffer      The buffer to place the Unicode or ASCII string.
88   @param  EndBuffer   The end of the input Buffer. No characters will be
89                       placed after that.
90   @param  Length      The count of character to be placed into Buffer.
91                       (Negative value indicates no buffer fill.)
92   @param  Character   The character to be placed into Buffer.
93   @param  Increment   The character increment in Buffer.
94 
95   @return Buffer.
96 
97 **/
98 CHAR8 *
BasePrintLibFillBuffer(OUT CHAR8 * Buffer,IN CHAR8 * EndBuffer,IN INTN Length,IN UINTN Character,IN INTN Increment)99 BasePrintLibFillBuffer (
100   OUT CHAR8   *Buffer,
101   IN  CHAR8   *EndBuffer,
102   IN  INTN    Length,
103   IN  UINTN   Character,
104   IN  INTN    Increment
105   )
106 {
107   INTN  Index;
108 
109   for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {
110     *Buffer = (CHAR8) Character;
111     if (Increment != 1) {
112       *(Buffer + 1) = (CHAR8)(Character >> 8);
113     }
114     Buffer += Increment;
115   }
116 
117   return Buffer;
118 }
119 
120 /**
121   Internal function that convert a number to a string in Buffer.
122 
123   Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.
124 
125   @param  Buffer    Location to place the ASCII string of Value.
126   @param  Value     The value to convert to a Decimal or Hexadecimal string in Buffer.
127   @param  Radix     Radix of the value
128 
129   @return A pointer to the end of buffer filled with ASCII string.
130 
131 **/
132 CHAR8 *
BasePrintLibValueToString(IN OUT CHAR8 * Buffer,IN INT64 Value,IN UINTN Radix)133 BasePrintLibValueToString (
134   IN OUT CHAR8  *Buffer,
135   IN INT64      Value,
136   IN UINTN      Radix
137   )
138 {
139   UINT32  Remainder;
140 
141   //
142   // Loop to convert one digit at a time in reverse order
143   //
144   *Buffer = 0;
145   do {
146     Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);
147     *(++Buffer) = mHexStr[Remainder];
148   } while (Value != 0);
149 
150   //
151   // Return pointer of the end of filled buffer.
152   //
153   return Buffer;
154 }
155 
156 /**
157   Internal function that converts a decimal value to a Null-terminated string.
158 
159   Converts the decimal number specified by Value to a Null-terminated
160   string specified by Buffer containing at most Width characters.
161   If Width is 0 then a width of  MAXIMUM_VALUE_CHARACTERS is assumed.
162   The total number of characters placed in Buffer is returned.
163   If the conversion contains more than Width characters, then only the first
164   Width characters are returned, and the total number of characters
165   required to perform the conversion is returned.
166   Additional conversion parameters are specified in Flags.
167   The Flags bit LEFT_JUSTIFY is always ignored.
168   All conversions are left justified in Buffer.
169   If Width is 0, PREFIX_ZERO is ignored in Flags.
170   If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
171   are inserted every 3rd digit starting from the right.
172   If Value is < 0, then the fist character in Buffer is a '-'.
173   If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
174   then Buffer is padded with '0' characters so the combination of the optional '-'
175   sign character, '0' characters, digit characters for Value, and the Null-terminator
176   add up to Width characters.
177 
178   If Buffer is NULL, then ASSERT().
179   If unsupported bits are set in Flags, then ASSERT().
180   If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
181 
182   @param  Buffer    The pointer to the output buffer for the produced Null-terminated
183                     string.
184   @param  Flags     The bitmask of flags that specify left justification, zero pad,
185                     and commas.
186   @param  Value     The 64-bit signed value to convert to a string.
187   @param  Width     The maximum number of characters to place in Buffer, not including
188                     the Null-terminator.
189   @param  Increment The character increment in Buffer.
190 
191   @return Total number of characters required to perform the conversion.
192 
193 **/
194 UINTN
BasePrintLibConvertValueToString(IN OUT CHAR8 * Buffer,IN UINTN Flags,IN INT64 Value,IN UINTN Width,IN UINTN Increment)195 BasePrintLibConvertValueToString (
196   IN OUT CHAR8   *Buffer,
197   IN UINTN       Flags,
198   IN INT64       Value,
199   IN UINTN       Width,
200   IN UINTN       Increment
201   )
202 {
203   CHAR8  *OriginalBuffer;
204   CHAR8  *EndBuffer;
205   CHAR8  ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
206   CHAR8  *ValueBufferPtr;
207   UINTN  Count;
208   UINTN  Digits;
209   UINTN  Index;
210   UINTN  Radix;
211 
212   //
213   // Make sure Buffer is not NULL and Width < MAXIMUM
214   //
215   ASSERT (Buffer != NULL);
216   ASSERT (Width < MAXIMUM_VALUE_CHARACTERS);
217   //
218   // Make sure Flags can only contain supported bits.
219   //
220   ASSERT ((Flags & ~(LEFT_JUSTIFY | COMMA_TYPE | PREFIX_ZERO | RADIX_HEX)) == 0);
221 
222   //
223   // If both COMMA_TYPE and RADIX_HEX are set, then ASSERT ()
224   //
225   ASSERT (((Flags & COMMA_TYPE) == 0) || ((Flags & RADIX_HEX) == 0));
226 
227   OriginalBuffer = Buffer;
228 
229   //
230   // Width is 0 or COMMA_TYPE is set, PREFIX_ZERO is ignored.
231   //
232   if (Width == 0 || (Flags & COMMA_TYPE) != 0) {
233     Flags &= ~((UINTN) PREFIX_ZERO);
234   }
235   //
236   // If Width is 0 then a width of  MAXIMUM_VALUE_CHARACTERS is assumed.
237   //
238   if (Width == 0) {
239     Width = MAXIMUM_VALUE_CHARACTERS - 1;
240   }
241   //
242   // Set the tag for the end of the input Buffer.
243   //
244   EndBuffer = Buffer + Width * Increment;
245 
246   //
247   // Convert decimal negative
248   //
249   if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {
250     Value = -Value;
251     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, '-', Increment);
252     Width--;
253   }
254 
255   //
256   // Count the length of the value string.
257   //
258   Radix = ((Flags & RADIX_HEX) == 0)? 10 : 16;
259   ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);
260   Count = ValueBufferPtr - ValueBuffer;
261 
262   //
263   // Append Zero
264   //
265   if ((Flags & PREFIX_ZERO) != 0) {
266     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Count, '0', Increment);
267   }
268 
269   //
270   // Print Comma type for every 3 characters
271   //
272   Digits = Count % 3;
273   if (Digits != 0) {
274     Digits = 3 - Digits;
275   }
276   for (Index = 0; Index < Count; Index++) {
277     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, *ValueBufferPtr--, Increment);
278     if ((Flags & COMMA_TYPE) != 0) {
279       Digits++;
280       if (Digits == 3) {
281         Digits = 0;
282         if ((Index + 1) < Count) {
283           Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', Increment);
284         }
285       }
286     }
287   }
288 
289   //
290   // Print Null-terminator
291   //
292   BasePrintLibFillBuffer (Buffer, EndBuffer + Increment, 1, 0, Increment);
293 
294   return ((Buffer - OriginalBuffer) / Increment);
295 }
296 
297 /**
298   Internal function that converts a decimal value to a Null-terminated string.
299 
300   Converts the decimal number specified by Value to a Null-terminated string
301   specified by Buffer containing at most Width characters. If Width is 0 then a
302   width of MAXIMUM_VALUE_CHARACTERS is assumed. If the conversion contains more
303   than Width characters, then only the first Width characters are placed in
304   Buffer. Additional conversion parameters are specified in Flags.
305   The Flags bit LEFT_JUSTIFY is always ignored.
306   All conversions are left justified in Buffer.
307   If Width is 0, PREFIX_ZERO is ignored in Flags.
308   If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and
309   commas are inserted every 3rd digit starting from the right.
310   If Value is < 0, then the fist character in Buffer is a '-'.
311   If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
312   then Buffer is padded with '0' characters so the combination of the optional
313   '-' sign character, '0' characters, digit characters for Value, and the
314   Null-terminator add up to Width characters.
315 
316   If an error would be returned, the function will ASSERT().
317 
318   @param  Buffer      The pointer to the output buffer for the produced
319                       Null-terminated string.
320   @param  BufferSize  The size of Buffer in bytes, including the
321                       Null-terminator.
322   @param  Flags       The bitmask of flags that specify left justification,
323                       zero pad, and commas.
324   @param  Value       The 64-bit signed value to convert to a string.
325   @param  Width       The maximum number of characters to place in Buffer,
326                       not including the Null-terminator.
327   @param  Increment   The character increment in Buffer.
328 
329   @retval RETURN_SUCCESS           The decimal value is converted.
330   @retval RETURN_BUFFER_TOO_SMALL  If BufferSize cannot hold the converted
331                                    value.
332   @retval RETURN_INVALID_PARAMETER If Buffer is NULL.
333                                    If Increment is 1 and
334                                    PcdMaximumAsciiStringLength is not zero,
335                                    BufferSize is greater than
336                                    PcdMaximumAsciiStringLength.
337                                    If Increment is not 1 and
338                                    PcdMaximumUnicodeStringLength is not zero,
339                                    BufferSize is greater than
340                                    (PcdMaximumUnicodeStringLength *
341                                    sizeof (CHAR16) + 1).
342                                    If unsupported bits are set in Flags.
343                                    If both COMMA_TYPE and RADIX_HEX are set in
344                                    Flags.
345                                    If Width >= MAXIMUM_VALUE_CHARACTERS.
346 
347 **/
348 RETURN_STATUS
BasePrintLibConvertValueToStringS(IN OUT CHAR8 * Buffer,IN UINTN BufferSize,IN UINTN Flags,IN INT64 Value,IN UINTN Width,IN UINTN Increment)349 BasePrintLibConvertValueToStringS (
350   IN OUT CHAR8   *Buffer,
351   IN UINTN       BufferSize,
352   IN UINTN       Flags,
353   IN INT64       Value,
354   IN UINTN       Width,
355   IN UINTN       Increment
356   )
357 {
358   CHAR8  *EndBuffer;
359   CHAR8  ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
360   CHAR8  *ValueBufferPtr;
361   UINTN  Count;
362   UINTN  Digits;
363   UINTN  Index;
364   UINTN  Radix;
365 
366   //
367   // 1. Buffer shall not be a null pointer.
368   //
369   SAFE_PRINT_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER);
370 
371   //
372   // 2. BufferSize shall not be greater than (RSIZE_MAX * sizeof (CHAR16)) for
373   //    Unicode output string or shall not be greater than ASCII_RSIZE_MAX for
374   //    Ascii output string.
375   //
376   if (Increment == 1) {
377     //
378     // Ascii output string
379     //
380     if (ASCII_RSIZE_MAX != 0) {
381       SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
382     }
383   } else {
384     //
385     // Unicode output string
386     //
387     if (RSIZE_MAX != 0) {
388       SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= RSIZE_MAX * sizeof (CHAR16) + 1), RETURN_INVALID_PARAMETER);
389     }
390   }
391 
392   //
393   // 3. Flags shall be set properly.
394   //
395   SAFE_PRINT_CONSTRAINT_CHECK (((Flags & ~(LEFT_JUSTIFY | COMMA_TYPE | PREFIX_ZERO | RADIX_HEX)) == 0), RETURN_INVALID_PARAMETER);
396   SAFE_PRINT_CONSTRAINT_CHECK ((((Flags & COMMA_TYPE) == 0) || ((Flags & RADIX_HEX) == 0)), RETURN_INVALID_PARAMETER);
397 
398   //
399   // 4. Width shall be smaller than MAXIMUM_VALUE_CHARACTERS.
400   //
401   SAFE_PRINT_CONSTRAINT_CHECK ((Width < MAXIMUM_VALUE_CHARACTERS), RETURN_INVALID_PARAMETER);
402 
403   //
404   // Width is 0 or COMMA_TYPE is set, PREFIX_ZERO is ignored.
405   //
406   if (Width == 0 || (Flags & COMMA_TYPE) != 0) {
407     Flags &= ~((UINTN) PREFIX_ZERO);
408   }
409   //
410   // If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
411   //
412   if (Width == 0) {
413     Width = MAXIMUM_VALUE_CHARACTERS - 1;
414   }
415 
416   //
417   // Count the characters of the output string.
418   //
419   Count = 0;
420   Radix = ((Flags & RADIX_HEX) == 0)? 10 : 16;
421 
422   if ((Flags & PREFIX_ZERO) != 0) {
423     Count = Width;
424   } else {
425     if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {
426       Count++;  // minus sign
427       ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, -Value, Radix);
428     } else {
429       ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);
430     }
431     Digits = ValueBufferPtr - ValueBuffer;
432     Count += Digits;
433 
434     if ((Flags & COMMA_TYPE) != 0) {
435       Count += (Digits - 1) / 3;  // commas
436     }
437   }
438 
439   Width = MIN (Count, Width);
440 
441   //
442   // 5. BufferSize shall be large enough to hold the converted string.
443   //
444   SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize >= (Width + 1) * Increment), RETURN_BUFFER_TOO_SMALL);
445 
446   //
447   // Set the tag for the end of the input Buffer.
448   //
449   EndBuffer = Buffer + Width * Increment;
450 
451   //
452   // Convert decimal negative
453   //
454   if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {
455     Value = -Value;
456     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, '-', Increment);
457     Width--;
458   }
459 
460   //
461   // Count the length of the value string.
462   //
463   ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);
464   Count = ValueBufferPtr - ValueBuffer;
465 
466   //
467   // Append Zero
468   //
469   if ((Flags & PREFIX_ZERO) != 0) {
470     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Count, '0', Increment);
471   }
472 
473   //
474   // Print Comma type for every 3 characters
475   //
476   Digits = Count % 3;
477   if (Digits != 0) {
478     Digits = 3 - Digits;
479   }
480   for (Index = 0; Index < Count; Index++) {
481     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, *ValueBufferPtr--, Increment);
482     if ((Flags & COMMA_TYPE) != 0) {
483       Digits++;
484       if (Digits == 3) {
485         Digits = 0;
486         if ((Index + 1) < Count) {
487           Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', Increment);
488         }
489       }
490     }
491   }
492 
493   //
494   // Print Null-terminator
495   //
496   BasePrintLibFillBuffer (Buffer, EndBuffer + Increment, 1, 0, Increment);
497 
498   return RETURN_SUCCESS;
499 }
500 
501 /**
502   Worker function that produces a Null-terminated string in an output buffer
503   based on a Null-terminated format string and a VA_LIST argument list.
504 
505   VSPrint function to process format and place the results in Buffer. Since a
506   VA_LIST is used this routine allows the nesting of Vararg routines. Thus
507   this is the main print working routine.
508 
509   If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
510 
511   @param[out] Buffer          The character buffer to print the results of the
512                               parsing of Format into.
513   @param[in]  BufferSize      The maximum number of characters to put into
514                               buffer.
515   @param[in]  Flags           Initial flags value.
516                               Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
517                               and COUNT_ONLY_NO_PRINT set.
518   @param[in]  Format          A Null-terminated format string.
519   @param[in]  VaListMarker    VA_LIST style variable argument list consumed by
520                               processing Format.
521   @param[in]  BaseListMarker  BASE_LIST style variable argument list consumed
522                               by processing Format.
523 
524   @return The number of characters printed not including the Null-terminator.
525           If COUNT_ONLY_NO_PRINT was set returns the same, but without any
526           modification to Buffer.
527 
528 **/
529 UINTN
BasePrintLibSPrintMarker(OUT CHAR8 * Buffer,IN UINTN BufferSize,IN UINTN Flags,IN CONST CHAR8 * Format,IN VA_LIST VaListMarker,OPTIONAL IN BASE_LIST BaseListMarker OPTIONAL)530 BasePrintLibSPrintMarker (
531   OUT CHAR8        *Buffer,
532   IN  UINTN        BufferSize,
533   IN  UINTN        Flags,
534   IN  CONST CHAR8  *Format,
535   IN  VA_LIST      VaListMarker,   OPTIONAL
536   IN  BASE_LIST    BaseListMarker  OPTIONAL
537   )
538 {
539   CHAR8             *OriginalBuffer;
540   CHAR8             *EndBuffer;
541   CHAR8             ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
542   UINT32            BytesPerOutputCharacter;
543   UINTN             BytesPerFormatCharacter;
544   UINTN             FormatMask;
545   UINTN             FormatCharacter;
546   UINTN             Width;
547   UINTN             Precision;
548   INT64             Value;
549   CONST CHAR8       *ArgumentString;
550   UINTN             Character;
551   GUID              *TmpGuid;
552   TIME              *TmpTime;
553   UINTN             Count;
554   UINTN             ArgumentMask;
555   INTN              BytesPerArgumentCharacter;
556   UINTN             ArgumentCharacter;
557   BOOLEAN           Done;
558   UINTN             Index;
559   CHAR8             Prefix;
560   BOOLEAN           ZeroPad;
561   BOOLEAN           Comma;
562   UINTN             Digits;
563   UINTN             Radix;
564   RETURN_STATUS     Status;
565   UINT32            GuidData1;
566   UINT16            GuidData2;
567   UINT16            GuidData3;
568   UINTN             LengthToReturn;
569 
570   //
571   // If you change this code be sure to match the 2 versions of this function.
572   // Nearly identical logic is found in the BasePrintLib and
573   // DxePrintLibPrint2Protocol (both PrintLib instances).
574   //
575 
576   //
577   // 1. Buffer shall not be a null pointer when both BufferSize > 0 and
578   //    COUNT_ONLY_NO_PRINT is not set in Flags.
579   //
580   if ((BufferSize > 0) && ((Flags & COUNT_ONLY_NO_PRINT) == 0)) {
581     SAFE_PRINT_CONSTRAINT_CHECK ((Buffer != NULL), 0);
582   }
583 
584   //
585   // 2. Format shall not be a null pointer when BufferSize > 0 or when
586   //    COUNT_ONLY_NO_PRINT is set in Flags.
587   //
588   if ((BufferSize > 0) || ((Flags & COUNT_ONLY_NO_PRINT) != 0)) {
589     SAFE_PRINT_CONSTRAINT_CHECK ((Format != NULL), 0);
590   }
591 
592   //
593   // 3. BufferSize shall not be greater than RSIZE_MAX for Unicode output or
594   //    ASCII_RSIZE_MAX for Ascii output.
595   //
596   if ((Flags & OUTPUT_UNICODE) != 0) {
597     if (RSIZE_MAX != 0) {
598       SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= RSIZE_MAX), 0);
599     }
600     BytesPerOutputCharacter = 2;
601   } else {
602     if (ASCII_RSIZE_MAX != 0) {
603       SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= ASCII_RSIZE_MAX), 0);
604     }
605     BytesPerOutputCharacter = 1;
606   }
607 
608   //
609   // 4. Format shall not contain more than RSIZE_MAX Unicode characters or
610   //    ASCII_RSIZE_MAX Ascii characters.
611   //
612   if ((Flags & FORMAT_UNICODE) != 0) {
613     if (RSIZE_MAX != 0) {
614       SAFE_PRINT_CONSTRAINT_CHECK ((StrnLenS ((CHAR16 *)Format, RSIZE_MAX + 1) <= RSIZE_MAX), 0);
615     }
616     BytesPerFormatCharacter = 2;
617     FormatMask = 0xffff;
618   } else {
619     if (ASCII_RSIZE_MAX != 0) {
620       SAFE_PRINT_CONSTRAINT_CHECK ((AsciiStrnLenS (Format, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), 0);
621     }
622     BytesPerFormatCharacter = 1;
623     FormatMask = 0xff;
624   }
625 
626   if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
627     if (BufferSize == 0) {
628       Buffer = NULL;
629     }
630   } else {
631     //
632     // We can run without a Buffer for counting only.
633     //
634     if (BufferSize == 0) {
635       return 0;
636     }
637   }
638 
639   LengthToReturn = 0;
640   EndBuffer = NULL;
641   OriginalBuffer = NULL;
642 
643   //
644   // Reserve space for the Null terminator.
645   //
646   if (Buffer != NULL) {
647     BufferSize--;
648     OriginalBuffer = Buffer;
649 
650     //
651     // Set the tag for the end of the input Buffer.
652     //
653     EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;
654   }
655 
656   //
657   // Get the first character from the format string
658   //
659   FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
660 
661   //
662   // Loop until the end of the format string is reached or the output buffer is full
663   //
664   while (FormatCharacter != 0) {
665     if ((Buffer != NULL) && (Buffer >= EndBuffer)) {
666       break;
667     }
668     //
669     // Clear all the flag bits except those that may have been passed in
670     //
671     Flags &= (UINTN) (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);
672 
673     //
674     // Set the default width to zero, and the default precision to 1
675     //
676     Width     = 0;
677     Precision = 1;
678     Prefix    = 0;
679     Comma     = FALSE;
680     ZeroPad   = FALSE;
681     Count     = 0;
682     Digits    = 0;
683 
684     switch (FormatCharacter) {
685     case '%':
686       //
687       // Parse Flags and Width
688       //
689       for (Done = FALSE; !Done; ) {
690         Format += BytesPerFormatCharacter;
691         FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
692         switch (FormatCharacter) {
693         case '.':
694           Flags |= PRECISION;
695           break;
696         case '-':
697           Flags |= LEFT_JUSTIFY;
698           break;
699         case '+':
700           Flags |= PREFIX_SIGN;
701           break;
702         case ' ':
703           Flags |= PREFIX_BLANK;
704           break;
705         case ',':
706           Flags |= COMMA_TYPE;
707           break;
708         case 'L':
709         case 'l':
710           Flags |= LONG_TYPE;
711           break;
712         case '*':
713           if ((Flags & PRECISION) == 0) {
714             Flags |= PAD_TO_WIDTH;
715             if (BaseListMarker == NULL) {
716               Width = VA_ARG (VaListMarker, UINTN);
717             } else {
718               Width = BASE_ARG (BaseListMarker, UINTN);
719             }
720           } else {
721             if (BaseListMarker == NULL) {
722               Precision = VA_ARG (VaListMarker, UINTN);
723             } else {
724               Precision = BASE_ARG (BaseListMarker, UINTN);
725             }
726           }
727           break;
728         case '0':
729           if ((Flags & PRECISION) == 0) {
730             Flags |= PREFIX_ZERO;
731           }
732         case '1':
733         case '2':
734         case '3':
735         case '4':
736         case '5':
737         case '6':
738         case '7':
739         case '8':
740         case '9':
741           for (Count = 0; ((FormatCharacter >= '0') &&  (FormatCharacter <= '9')); ){
742             Count = (Count * 10) + FormatCharacter - '0';
743             Format += BytesPerFormatCharacter;
744             FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
745           }
746           Format -= BytesPerFormatCharacter;
747           if ((Flags & PRECISION) == 0) {
748             Flags |= PAD_TO_WIDTH;
749             Width = Count;
750           } else {
751             Precision = Count;
752           }
753           break;
754 
755         case '\0':
756           //
757           // Make no output if Format string terminates unexpectedly when
758           // looking up for flag, width, precision and type.
759           //
760           Format   -= BytesPerFormatCharacter;
761           Precision = 0;
762           //
763           // break skipped on purpose.
764           //
765         default:
766           Done = TRUE;
767           break;
768         }
769       }
770 
771       //
772       // Handle each argument type
773       //
774       switch (FormatCharacter) {
775       case 'p':
776         //
777         // Flag space, +, 0, L & l are invalid for type p.
778         //
779         Flags &= ~((UINTN) (PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE));
780         if (sizeof (VOID *) > 4) {
781           Flags |= LONG_TYPE;
782         }
783         //
784         // break skipped on purpose
785         //
786       case 'X':
787         Flags |= PREFIX_ZERO;
788         //
789         // break skipped on purpose
790         //
791       case 'x':
792         Flags |= RADIX_HEX;
793         //
794         // break skipped on purpose
795         //
796       case 'u':
797         if ((Flags & RADIX_HEX) == 0) {
798           Flags &= ~((UINTN) (PREFIX_SIGN));
799           Flags |= UNSIGNED_TYPE;
800         }
801         //
802         // break skipped on purpose
803         //
804       case 'd':
805         if ((Flags & LONG_TYPE) == 0) {
806           //
807           // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
808           // This assumption is made so the format string definition is compatible with the ANSI C
809           // Specification for formatted strings.  It is recommended that the Base Types be used
810           // everywhere, but in this one case, compliance with ANSI C is more important, and
811           // provides an implementation that is compatible with that largest possible set of CPU
812           // architectures.  This is why the type "int" is used in this one case.
813           //
814           if (BaseListMarker == NULL) {
815             Value = VA_ARG (VaListMarker, int);
816           } else {
817             Value = BASE_ARG (BaseListMarker, int);
818           }
819         } else {
820           if (BaseListMarker == NULL) {
821             Value = VA_ARG (VaListMarker, INT64);
822           } else {
823             Value = BASE_ARG (BaseListMarker, INT64);
824           }
825         }
826         if ((Flags & PREFIX_BLANK) != 0) {
827           Prefix = ' ';
828         }
829         if ((Flags & PREFIX_SIGN) != 0) {
830           Prefix = '+';
831         }
832         if ((Flags & COMMA_TYPE) != 0) {
833           Comma = TRUE;
834         }
835         if ((Flags & RADIX_HEX) == 0) {
836           Radix = 10;
837           if (Comma) {
838             Flags &= ~((UINTN) PREFIX_ZERO);
839             Precision = 1;
840           }
841           if (Value < 0 && (Flags & UNSIGNED_TYPE) == 0) {
842             Flags |= PREFIX_SIGN;
843             Prefix = '-';
844             Value = -Value;
845           } else if ((Flags & UNSIGNED_TYPE) != 0 && (Flags & LONG_TYPE) == 0) {
846             //
847             // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
848             // This assumption is made so the format string definition is compatible with the ANSI C
849             // Specification for formatted strings.  It is recommended that the Base Types be used
850             // everywhere, but in this one case, compliance with ANSI C is more important, and
851             // provides an implementation that is compatible with that largest possible set of CPU
852             // architectures.  This is why the type "unsigned int" is used in this one case.
853             //
854             Value = (unsigned int)Value;
855           }
856         } else {
857           Radix = 16;
858           Comma = FALSE;
859           if ((Flags & LONG_TYPE) == 0 && Value < 0) {
860             //
861             // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
862             // This assumption is made so the format string definition is compatible with the ANSI C
863             // Specification for formatted strings.  It is recommended that the Base Types be used
864             // everywhere, but in this one case, compliance with ANSI C is more important, and
865             // provides an implementation that is compatible with that largest possible set of CPU
866             // architectures.  This is why the type "unsigned int" is used in this one case.
867             //
868             Value = (unsigned int)Value;
869           }
870         }
871         //
872         // Convert Value to a reversed string
873         //
874         Count = BasePrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;
875         if (Value == 0 && Precision == 0) {
876           Count = 0;
877         }
878         ArgumentString = (CHAR8 *)ValueBuffer + Count;
879 
880         Digits = Count % 3;
881         if (Digits != 0) {
882           Digits = 3 - Digits;
883         }
884         if (Comma && Count != 0) {
885           Count += ((Count - 1) / 3);
886         }
887         if (Prefix != 0) {
888           Count++;
889           Precision++;
890         }
891         Flags |= ARGUMENT_REVERSED;
892         ZeroPad = TRUE;
893         if ((Flags & PREFIX_ZERO) != 0) {
894           if ((Flags & LEFT_JUSTIFY) == 0) {
895             if ((Flags & PAD_TO_WIDTH) != 0) {
896               if ((Flags & PRECISION) == 0) {
897                 Precision = Width;
898               }
899             }
900           }
901         }
902         break;
903 
904       case 's':
905       case 'S':
906         Flags |= ARGUMENT_UNICODE;
907         //
908         // break skipped on purpose
909         //
910       case 'a':
911         if (BaseListMarker == NULL) {
912           ArgumentString = VA_ARG (VaListMarker, CHAR8 *);
913         } else {
914           ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);
915         }
916         if (ArgumentString == NULL) {
917           Flags &= ~((UINTN) ARGUMENT_UNICODE);
918           ArgumentString = "<null string>";
919         }
920         //
921         // Set the default precision for string to be zero if not specified.
922         //
923         if ((Flags & PRECISION) == 0) {
924           Precision = 0;
925         }
926         break;
927 
928       case 'c':
929         if (BaseListMarker == NULL) {
930           Character = VA_ARG (VaListMarker, UINTN) & 0xffff;
931         } else {
932           Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;
933         }
934         ArgumentString = (CHAR8 *)&Character;
935         Flags |= ARGUMENT_UNICODE;
936         break;
937 
938       case 'g':
939         if (BaseListMarker == NULL) {
940           TmpGuid = VA_ARG (VaListMarker, GUID *);
941         } else {
942           TmpGuid = BASE_ARG (BaseListMarker, GUID *);
943         }
944         if (TmpGuid == NULL) {
945           ArgumentString = "<null guid>";
946         } else {
947           GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));
948           GuidData2 = ReadUnaligned16 (&(TmpGuid->Data2));
949           GuidData3 = ReadUnaligned16 (&(TmpGuid->Data3));
950           BasePrintLibSPrint (
951             ValueBuffer,
952             MAXIMUM_VALUE_CHARACTERS,
953             0,
954             "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
955             GuidData1,
956             GuidData2,
957             GuidData3,
958             TmpGuid->Data4[0],
959             TmpGuid->Data4[1],
960             TmpGuid->Data4[2],
961             TmpGuid->Data4[3],
962             TmpGuid->Data4[4],
963             TmpGuid->Data4[5],
964             TmpGuid->Data4[6],
965             TmpGuid->Data4[7]
966             );
967           ArgumentString = ValueBuffer;
968         }
969         break;
970 
971       case 't':
972         if (BaseListMarker == NULL) {
973           TmpTime = VA_ARG (VaListMarker, TIME *);
974         } else {
975           TmpTime = BASE_ARG (BaseListMarker, TIME *);
976         }
977         if (TmpTime == NULL) {
978           ArgumentString = "<null time>";
979         } else {
980           BasePrintLibSPrint (
981             ValueBuffer,
982             MAXIMUM_VALUE_CHARACTERS,
983             0,
984             "%02d/%02d/%04d  %02d:%02d",
985             TmpTime->Month,
986             TmpTime->Day,
987             TmpTime->Year,
988             TmpTime->Hour,
989             TmpTime->Minute
990             );
991           ArgumentString = ValueBuffer;
992         }
993         break;
994 
995       case 'r':
996         if (BaseListMarker == NULL) {
997           Status = VA_ARG (VaListMarker, RETURN_STATUS);
998         } else {
999           Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
1000         }
1001         ArgumentString = ValueBuffer;
1002         if (RETURN_ERROR (Status)) {
1003           //
1004           // Clear error bit
1005           //
1006           Index = Status & ~MAX_BIT;
1007           if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
1008             ArgumentString = mErrorString [Index - 1];
1009           }
1010         } else {
1011           Index = Status;
1012           if (Index <= WARNING_STATUS_NUMBER) {
1013             ArgumentString = mWarningString [Index];
1014           }
1015         }
1016         if (ArgumentString == ValueBuffer) {
1017           BasePrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
1018         }
1019         break;
1020 
1021       case '\r':
1022         Format += BytesPerFormatCharacter;
1023         FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
1024         if (FormatCharacter == '\n') {
1025           //
1026           // Translate '\r\n' to '\r\n'
1027           //
1028           ArgumentString = "\r\n";
1029         } else {
1030           //
1031           // Translate '\r' to '\r'
1032           //
1033           ArgumentString = "\r";
1034           Format   -= BytesPerFormatCharacter;
1035         }
1036         break;
1037 
1038       case '\n':
1039         //
1040         // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
1041         //
1042         ArgumentString = "\r\n";
1043         Format += BytesPerFormatCharacter;
1044         FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
1045         if (FormatCharacter != '\r') {
1046           Format   -= BytesPerFormatCharacter;
1047         }
1048         break;
1049 
1050       case '%':
1051       default:
1052         //
1053         // if the type is '%' or unknown, then print it to the screen
1054         //
1055         ArgumentString = (CHAR8 *)&FormatCharacter;
1056         Flags |= ARGUMENT_UNICODE;
1057         break;
1058       }
1059       break;
1060 
1061     case '\r':
1062       Format += BytesPerFormatCharacter;
1063       FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
1064       if (FormatCharacter == '\n') {
1065         //
1066         // Translate '\r\n' to '\r\n'
1067         //
1068         ArgumentString = "\r\n";
1069       } else {
1070         //
1071         // Translate '\r' to '\r'
1072         //
1073         ArgumentString = "\r";
1074         Format   -= BytesPerFormatCharacter;
1075       }
1076       break;
1077 
1078     case '\n':
1079       //
1080       // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
1081       //
1082       ArgumentString = "\r\n";
1083       Format += BytesPerFormatCharacter;
1084       FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
1085       if (FormatCharacter != '\r') {
1086         Format   -= BytesPerFormatCharacter;
1087       }
1088       break;
1089 
1090     default:
1091       ArgumentString = (CHAR8 *)&FormatCharacter;
1092       Flags |= ARGUMENT_UNICODE;
1093       break;
1094     }
1095 
1096     //
1097     // Retrieve the ArgumentString attriubutes
1098     //
1099     if ((Flags & ARGUMENT_UNICODE) != 0) {
1100       ArgumentMask = 0xffff;
1101       BytesPerArgumentCharacter = 2;
1102     } else {
1103       ArgumentMask = 0xff;
1104       BytesPerArgumentCharacter = 1;
1105     }
1106     if ((Flags & ARGUMENT_REVERSED) != 0) {
1107       BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
1108     } else {
1109       //
1110       // Compute the number of characters in ArgumentString and store it in Count
1111       // ArgumentString is either null-terminated, or it contains Precision characters
1112       //
1113       for (Count = 0;
1114             (ArgumentString[Count * BytesPerArgumentCharacter] != '\0' ||
1115              (BytesPerArgumentCharacter > 1 &&
1116               ArgumentString[Count * BytesPerArgumentCharacter + 1]!= '\0')) &&
1117             (Count < Precision || ((Flags & PRECISION) == 0));
1118               Count++) {
1119         ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
1120         if (ArgumentCharacter == 0) {
1121           break;
1122         }
1123       }
1124     }
1125 
1126     if (Precision < Count) {
1127       Precision = Count;
1128     }
1129 
1130     //
1131     // Pad before the string
1132     //
1133     if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
1134       LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
1135       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
1136         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
1137       }
1138     }
1139 
1140     if (ZeroPad) {
1141       if (Prefix != 0) {
1142         LengthToReturn += (1 * BytesPerOutputCharacter);
1143         if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
1144           Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
1145         }
1146       }
1147       LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
1148       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
1149         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);
1150       }
1151     } else {
1152       LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
1153       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
1154         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);
1155       }
1156       if (Prefix != 0) {
1157         LengthToReturn += (1 * BytesPerOutputCharacter);
1158         if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
1159           Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
1160         }
1161       }
1162     }
1163 
1164     //
1165     // Output the Prefix character if it is present
1166     //
1167     Index = 0;
1168     if (Prefix != 0) {
1169       Index++;
1170     }
1171 
1172     //
1173     // Copy the string into the output buffer performing the required type conversions
1174     //
1175     while (Index < Count &&
1176            (ArgumentString[0] != '\0' ||
1177             (BytesPerArgumentCharacter > 1 && ArgumentString[1] != '\0'))) {
1178       ArgumentCharacter = ((*ArgumentString & 0xff) | (((UINT8)*(ArgumentString + 1)) << 8)) & ArgumentMask;
1179 
1180       LengthToReturn += (1 * BytesPerOutputCharacter);
1181       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
1182         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
1183       }
1184       ArgumentString    += BytesPerArgumentCharacter;
1185       Index++;
1186       if (Comma) {
1187         Digits++;
1188         if (Digits == 3) {
1189           Digits = 0;
1190           Index++;
1191           if (Index < Count) {
1192             LengthToReturn += (1 * BytesPerOutputCharacter);
1193             if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
1194               Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);
1195             }
1196           }
1197         }
1198       }
1199     }
1200 
1201     //
1202     // Pad after the string
1203     //
1204     if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
1205       LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
1206       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
1207         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
1208       }
1209     }
1210 
1211     //
1212     // Get the next character from the format string
1213     //
1214     Format += BytesPerFormatCharacter;
1215 
1216     //
1217     // Get the next character from the format string
1218     //
1219     FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
1220   }
1221 
1222   if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
1223     return (LengthToReturn / BytesPerOutputCharacter);
1224   }
1225 
1226   ASSERT (Buffer != NULL);
1227   //
1228   // Null terminate the Unicode or ASCII string
1229   //
1230   BasePrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);
1231 
1232   return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
1233 }
1234 
1235 /**
1236   Worker function that produces a Null-terminated string in an output buffer
1237   based on a Null-terminated format string and variable argument list.
1238 
1239   VSPrint function to process format and place the results in Buffer. Since a
1240   VA_LIST is used this routine allows the nesting of Vararg routines. Thus
1241   this is the main print working routine
1242 
1243   @param  StartOfBuffer The character buffer to print the results of the parsing
1244                         of Format into.
1245   @param  BufferSize    The maximum number of characters to put into buffer.
1246                         Zero means no limit.
1247   @param  Flags         Initial flags value.
1248                         Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
1249   @param  FormatString  A Null-terminated format string.
1250   @param  ...           The variable argument list.
1251 
1252   @return The number of characters printed.
1253 
1254 **/
1255 UINTN
1256 EFIAPI
BasePrintLibSPrint(OUT CHAR8 * StartOfBuffer,IN UINTN BufferSize,IN UINTN Flags,IN CONST CHAR8 * FormatString,...)1257 BasePrintLibSPrint (
1258   OUT CHAR8        *StartOfBuffer,
1259   IN  UINTN        BufferSize,
1260   IN  UINTN        Flags,
1261   IN  CONST CHAR8  *FormatString,
1262   ...
1263   )
1264 {
1265   VA_LIST  Marker;
1266   UINTN    NumberOfPrinted;
1267 
1268   VA_START (Marker, FormatString);
1269   NumberOfPrinted = BasePrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);
1270   VA_END (Marker);
1271   return NumberOfPrinted;
1272 }
1273