1 /** @file
2   Safe String functions.
3 
4   Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php.
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include <Base.h>
16 #include <Library/DebugLib.h>
17 #include <Library/PcdLib.h>
18 #include <Library/BaseLib.h>
19 
20 #define RSIZE_MAX  (PcdGet32 (PcdMaximumUnicodeStringLength))
21 
22 #define ASCII_RSIZE_MAX  (PcdGet32 (PcdMaximumAsciiStringLength))
23 
24 #define SAFE_STRING_CONSTRAINT_CHECK(Expression, Status)  \
25   do { \
26     ASSERT (Expression); \
27     if (!(Expression)) { \
28       return Status; \
29     } \
30   } while (FALSE)
31 
32 /**
33   Returns if 2 memory blocks are overlapped.
34 
35   @param  Base1  Base address of 1st memory block.
36   @param  Size1  Size of 1st memory block.
37   @param  Base2  Base address of 2nd memory block.
38   @param  Size2  Size of 2nd memory block.
39 
40   @retval TRUE  2 memory blocks are overlapped.
41   @retval FALSE 2 memory blocks are not overlapped.
42 **/
43 BOOLEAN
InternalSafeStringIsOverlap(IN VOID * Base1,IN UINTN Size1,IN VOID * Base2,IN UINTN Size2)44 InternalSafeStringIsOverlap (
45   IN VOID    *Base1,
46   IN UINTN   Size1,
47   IN VOID    *Base2,
48   IN UINTN   Size2
49   )
50 {
51   if ((((UINTN)Base1 >= (UINTN)Base2) && ((UINTN)Base1 < (UINTN)Base2 + Size2)) ||
52       (((UINTN)Base2 >= (UINTN)Base1) && ((UINTN)Base2 < (UINTN)Base1 + Size1))) {
53     return TRUE;
54   }
55   return FALSE;
56 }
57 
58 /**
59   Returns if 2 Unicode strings are not overlapped.
60 
61   @param  Str1   Start address of 1st Unicode string.
62   @param  Size1  The number of char in 1st Unicode string,
63                  including terminating null char.
64   @param  Str2   Start address of 2nd Unicode string.
65   @param  Size2  The number of char in 2nd Unicode string,
66                  including terminating null char.
67 
68   @retval TRUE  2 Unicode strings are NOT overlapped.
69   @retval FALSE 2 Unicode strings are overlapped.
70 **/
71 BOOLEAN
InternalSafeStringNoStrOverlap(IN CHAR16 * Str1,IN UINTN Size1,IN CHAR16 * Str2,IN UINTN Size2)72 InternalSafeStringNoStrOverlap (
73   IN CHAR16  *Str1,
74   IN UINTN   Size1,
75   IN CHAR16  *Str2,
76   IN UINTN   Size2
77   )
78 {
79   return !InternalSafeStringIsOverlap (Str1, Size1 * sizeof(CHAR16), Str2, Size2 * sizeof(CHAR16));
80 }
81 
82 /**
83   Returns if 2 Ascii strings are not overlapped.
84 
85   @param  Str1   Start address of 1st Ascii string.
86   @param  Size1  The number of char in 1st Ascii string,
87                  including terminating null char.
88   @param  Str2   Start address of 2nd Ascii string.
89   @param  Size2  The number of char in 2nd Ascii string,
90                  including terminating null char.
91 
92   @retval TRUE  2 Ascii strings are NOT overlapped.
93   @retval FALSE 2 Ascii strings are overlapped.
94 **/
95 BOOLEAN
InternalSafeStringNoAsciiStrOverlap(IN CHAR8 * Str1,IN UINTN Size1,IN CHAR8 * Str2,IN UINTN Size2)96 InternalSafeStringNoAsciiStrOverlap (
97   IN CHAR8   *Str1,
98   IN UINTN   Size1,
99   IN CHAR8   *Str2,
100   IN UINTN   Size2
101   )
102 {
103   return !InternalSafeStringIsOverlap (Str1, Size1, Str2, Size2);
104 }
105 
106 /**
107   Returns the length of a Null-terminated Unicode string.
108 
109   This function is similar as strlen_s defined in C11.
110 
111   If String is not aligned on a 16-bit boundary, then ASSERT().
112 
113   @param  String   A pointer to a Null-terminated Unicode string.
114   @param  MaxSize  The maximum number of Destination Unicode
115                    char, including terminating null char.
116 
117   @retval 0        If String is NULL.
118   @retval MaxSize  If there is no null character in the first MaxSize characters of String.
119   @return The number of characters that percede the terminating null character.
120 
121 **/
122 UINTN
123 EFIAPI
StrnLenS(IN CONST CHAR16 * String,IN UINTN MaxSize)124 StrnLenS (
125   IN CONST CHAR16              *String,
126   IN UINTN                     MaxSize
127   )
128 {
129   UINTN                             Length;
130 
131   ASSERT (((UINTN) String & BIT0) == 0);
132 
133   //
134   // If String is a null pointer, then the StrnLenS function returns zero.
135   //
136   if (String == NULL) {
137     return 0;
138   }
139 
140   //
141   // Otherwise, the StrnLenS function returns the number of characters that precede the
142   // terminating null character. If there is no null character in the first MaxSize characters of
143   // String then StrnLenS returns MaxSize. At most the first MaxSize characters of String shall
144   // be accessed by StrnLenS.
145   //
146   Length = 0;
147   while (String[Length] != 0) {
148     if (Length >= MaxSize - 1) {
149       return MaxSize;
150     }
151     Length++;
152   }
153   return Length;
154 }
155 
156 /**
157   Copies the string pointed to by Source (including the terminating null char)
158   to the array pointed to by Destination.
159 
160   This function is similar as strcpy_s defined in C11.
161 
162   If Destination is not aligned on a 16-bit boundary, then ASSERT().
163   If Source is not aligned on a 16-bit boundary, then ASSERT().
164   If an error would be returned, then the function will also ASSERT().
165 
166   If an error is returned, then the Destination is unmodified.
167 
168   @param  Destination              A pointer to a Null-terminated Unicode string.
169   @param  DestMax                  The maximum number of Destination Unicode
170                                    char, including terminating null char.
171   @param  Source                   A pointer to a Null-terminated Unicode string.
172 
173   @retval RETURN_SUCCESS           String is copied.
174   @retval RETURN_BUFFER_TOO_SMALL  If DestMax is NOT greater than StrLen(Source).
175   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
176                                    If Source is NULL.
177                                    If PcdMaximumUnicodeStringLength is not zero,
178                                     and DestMax is greater than
179                                     PcdMaximumUnicodeStringLength.
180                                    If DestMax is 0.
181   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
182 **/
183 RETURN_STATUS
184 EFIAPI
StrCpyS(OUT CHAR16 * Destination,IN UINTN DestMax,IN CONST CHAR16 * Source)185 StrCpyS (
186   OUT CHAR16       *Destination,
187   IN  UINTN        DestMax,
188   IN  CONST CHAR16 *Source
189   )
190 {
191   UINTN            SourceLen;
192 
193   ASSERT (((UINTN) Destination & BIT0) == 0);
194   ASSERT (((UINTN) Source & BIT0) == 0);
195 
196   //
197   // 1. Neither Destination nor Source shall be a null pointer.
198   //
199   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
200   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
201 
202   //
203   // 2. DestMax shall not be greater than RSIZE_MAX.
204   //
205   if (RSIZE_MAX != 0) {
206     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
207   }
208 
209   //
210   // 3. DestMax shall not equal zero.
211   //
212   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
213 
214   //
215   // 4. DestMax shall be greater than StrnLenS(Source, DestMax).
216   //
217   SourceLen = StrnLenS (Source, DestMax);
218   SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);
219 
220   //
221   // 5. Copying shall not take place between objects that overlap.
222   //
223   SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
224 
225   //
226   // The StrCpyS function copies the string pointed to by Source (including the terminating
227   // null character) into the array pointed to by Destination.
228   //
229   while (*Source != 0) {
230     *(Destination++) = *(Source++);
231   }
232   *Destination = 0;
233 
234   return RETURN_SUCCESS;
235 }
236 
237 /**
238   Copies not more than Length successive char from the string pointed to by
239   Source to the array pointed to by Destination. If no null char is copied from
240   Source, then Destination[Length] is always set to null.
241 
242   This function is similar as strncpy_s defined in C11.
243 
244   If Length > 0 and Destination is not aligned on a 16-bit boundary, then ASSERT().
245   If Length > 0 and Source is not aligned on a 16-bit boundary, then ASSERT().
246   If an error would be returned, then the function will also ASSERT().
247 
248   If an error is returned, then the Destination is unmodified.
249 
250   @param  Destination              A pointer to a Null-terminated Unicode string.
251   @param  DestMax                  The maximum number of Destination Unicode
252                                    char, including terminating null char.
253   @param  Source                   A pointer to a Null-terminated Unicode string.
254   @param  Length                   The maximum number of Unicode characters to copy.
255 
256   @retval RETURN_SUCCESS           String is copied.
257   @retval RETURN_BUFFER_TOO_SMALL  If DestMax is NOT greater than
258                                    MIN(StrLen(Source), Length).
259   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
260                                    If Source is NULL.
261                                    If PcdMaximumUnicodeStringLength is not zero,
262                                     and DestMax is greater than
263                                     PcdMaximumUnicodeStringLength.
264                                    If DestMax is 0.
265   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
266 **/
267 RETURN_STATUS
268 EFIAPI
StrnCpyS(OUT CHAR16 * Destination,IN UINTN DestMax,IN CONST CHAR16 * Source,IN UINTN Length)269 StrnCpyS (
270   OUT CHAR16       *Destination,
271   IN  UINTN        DestMax,
272   IN  CONST CHAR16 *Source,
273   IN  UINTN        Length
274   )
275 {
276   UINTN            SourceLen;
277 
278   ASSERT (((UINTN) Destination & BIT0) == 0);
279   ASSERT (((UINTN) Source & BIT0) == 0);
280 
281   //
282   // 1. Neither Destination nor Source shall be a null pointer.
283   //
284   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
285   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
286 
287   //
288   // 2. Neither DestMax nor Length shall be greater than RSIZE_MAX
289   //
290   if (RSIZE_MAX != 0) {
291     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
292     SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
293   }
294 
295   //
296   // 3. DestMax shall not equal zero.
297   //
298   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
299 
300   //
301   // 4. If Length is not less than DestMax, then DestMax shall be greater than StrnLenS(Source, DestMax).
302   //
303   SourceLen = StrnLenS (Source, DestMax);
304   if (Length >= DestMax) {
305     SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);
306   }
307 
308   //
309   // 5. Copying shall not take place between objects that overlap.
310   //
311   if (SourceLen > Length) {
312     SourceLen = Length;
313   }
314   SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
315 
316   //
317   // The StrnCpyS function copies not more than Length successive characters (characters that
318   // follow a null character are not copied) from the array pointed to by Source to the array
319   // pointed to by Destination. If no null character was copied from Source, then Destination[Length] is set to a null
320   // character.
321   //
322   while ((*Source != 0) && (SourceLen > 0)) {
323     *(Destination++) = *(Source++);
324     SourceLen--;
325   }
326   *Destination = 0;
327 
328   return RETURN_SUCCESS;
329 }
330 
331 /**
332   Appends a copy of the string pointed to by Source (including the terminating
333   null char) to the end of the string pointed to by Destination.
334 
335   This function is similar as strcat_s defined in C11.
336 
337   If Destination is not aligned on a 16-bit boundary, then ASSERT().
338   If Source is not aligned on a 16-bit boundary, then ASSERT().
339   If an error would be returned, then the function will also ASSERT().
340 
341   If an error is returned, then the Destination is unmodified.
342 
343   @param  Destination              A pointer to a Null-terminated Unicode string.
344   @param  DestMax                  The maximum number of Destination Unicode
345                                    char, including terminating null char.
346   @param  Source                   A pointer to a Null-terminated Unicode string.
347 
348   @retval RETURN_SUCCESS           String is appended.
349   @retval RETURN_BAD_BUFFER_SIZE   If DestMax is NOT greater than
350                                    StrLen(Destination).
351   @retval RETURN_BUFFER_TOO_SMALL  If (DestMax - StrLen(Destination)) is NOT
352                                    greater than StrLen(Source).
353   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
354                                    If Source is NULL.
355                                    If PcdMaximumUnicodeStringLength is not zero,
356                                     and DestMax is greater than
357                                     PcdMaximumUnicodeStringLength.
358                                    If DestMax is 0.
359   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
360 **/
361 RETURN_STATUS
362 EFIAPI
StrCatS(IN OUT CHAR16 * Destination,IN UINTN DestMax,IN CONST CHAR16 * Source)363 StrCatS (
364   IN OUT CHAR16       *Destination,
365   IN     UINTN        DestMax,
366   IN     CONST CHAR16 *Source
367   )
368 {
369   UINTN               DestLen;
370   UINTN               CopyLen;
371   UINTN               SourceLen;
372 
373   ASSERT (((UINTN) Destination & BIT0) == 0);
374   ASSERT (((UINTN) Source & BIT0) == 0);
375 
376   //
377   // Let CopyLen denote the value DestMax - StrnLenS(Destination, DestMax) upon entry to StrCatS.
378   //
379   DestLen = StrnLenS (Destination, DestMax);
380   CopyLen = DestMax - DestLen;
381 
382   //
383   // 1. Neither Destination nor Source shall be a null pointer.
384   //
385   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
386   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
387 
388   //
389   // 2. DestMax shall not be greater than RSIZE_MAX.
390   //
391   if (RSIZE_MAX != 0) {
392     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
393   }
394 
395   //
396   // 3. DestMax shall not equal zero.
397   //
398   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
399 
400   //
401   // 4. CopyLen shall not equal zero.
402   //
403   SAFE_STRING_CONSTRAINT_CHECK ((CopyLen != 0), RETURN_BAD_BUFFER_SIZE);
404 
405   //
406   // 5. CopyLen shall be greater than StrnLenS(Source, CopyLen).
407   //
408   SourceLen = StrnLenS (Source, CopyLen);
409   SAFE_STRING_CONSTRAINT_CHECK ((CopyLen > SourceLen), RETURN_BUFFER_TOO_SMALL);
410 
411   //
412   // 6. Copying shall not take place between objects that overlap.
413   //
414   SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
415 
416   //
417   // The StrCatS function appends a copy of the string pointed to by Source (including the
418   // terminating null character) to the end of the string pointed to by Destination. The initial character
419   // from Source overwrites the null character at the end of Destination.
420   //
421   Destination = Destination + DestLen;
422   while (*Source != 0) {
423     *(Destination++) = *(Source++);
424   }
425   *Destination = 0;
426 
427   return RETURN_SUCCESS;
428 }
429 
430 /**
431   Appends not more than Length successive char from the string pointed to by
432   Source to the end of the string pointed to by Destination. If no null char is
433   copied from Source, then Destination[StrLen(Destination) + Length] is always
434   set to null.
435 
436   This function is similar as strncat_s defined in C11.
437 
438   If Destination is not aligned on a 16-bit boundary, then ASSERT().
439   If Source is not aligned on a 16-bit boundary, then ASSERT().
440   If an error would be returned, then the function will also ASSERT().
441 
442   If an error is returned, then the Destination is unmodified.
443 
444   @param  Destination              A pointer to a Null-terminated Unicode string.
445   @param  DestMax                  The maximum number of Destination Unicode
446                                    char, including terminating null char.
447   @param  Source                   A pointer to a Null-terminated Unicode string.
448   @param  Length                   The maximum number of Unicode characters to copy.
449 
450   @retval RETURN_SUCCESS           String is appended.
451   @retval RETURN_BAD_BUFFER_SIZE   If DestMax is NOT greater than
452                                    StrLen(Destination).
453   @retval RETURN_BUFFER_TOO_SMALL  If (DestMax - StrLen(Destination)) is NOT
454                                    greater than MIN(StrLen(Source), Length).
455   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
456                                    If Source is NULL.
457                                    If PcdMaximumUnicodeStringLength is not zero,
458                                     and DestMax is greater than
459                                     PcdMaximumUnicodeStringLength.
460                                    If DestMax is 0.
461   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
462 **/
463 RETURN_STATUS
464 EFIAPI
StrnCatS(IN OUT CHAR16 * Destination,IN UINTN DestMax,IN CONST CHAR16 * Source,IN UINTN Length)465 StrnCatS (
466   IN OUT CHAR16       *Destination,
467   IN     UINTN        DestMax,
468   IN     CONST CHAR16 *Source,
469   IN     UINTN        Length
470   )
471 {
472   UINTN               DestLen;
473   UINTN               CopyLen;
474   UINTN               SourceLen;
475 
476   ASSERT (((UINTN) Destination & BIT0) == 0);
477   ASSERT (((UINTN) Source & BIT0) == 0);
478 
479   //
480   // Let CopyLen denote the value DestMax - StrnLenS(Destination, DestMax) upon entry to StrnCatS.
481   //
482   DestLen = StrnLenS (Destination, DestMax);
483   CopyLen = DestMax - DestLen;
484 
485   //
486   // 1. Neither Destination nor Source shall be a null pointer.
487   //
488   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
489   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
490 
491   //
492   // 2. Neither DestMax nor Length shall be greater than RSIZE_MAX.
493   //
494   if (RSIZE_MAX != 0) {
495     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
496     SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
497   }
498 
499   //
500   // 3. DestMax shall not equal zero.
501   //
502   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
503 
504   //
505   // 4. CopyLen shall not equal zero.
506   //
507   SAFE_STRING_CONSTRAINT_CHECK ((CopyLen != 0), RETURN_BAD_BUFFER_SIZE);
508 
509   //
510   // 5. If Length is not less than CopyLen, then CopyLen shall be greater than StrnLenS(Source, CopyLen).
511   //
512   SourceLen = StrnLenS (Source, CopyLen);
513   if (Length >= CopyLen) {
514     SAFE_STRING_CONSTRAINT_CHECK ((CopyLen > SourceLen), RETURN_BUFFER_TOO_SMALL);
515   }
516 
517   //
518   // 6. Copying shall not take place between objects that overlap.
519   //
520   if (SourceLen > Length) {
521     SourceLen = Length;
522   }
523   SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
524 
525   //
526   // The StrnCatS function appends not more than Length successive characters (characters
527   // that follow a null character are not copied) from the array pointed to by Source to the end of
528   // the string pointed to by Destination. The initial character from Source overwrites the null character at
529   // the end of Destination. If no null character was copied from Source, then Destination[DestMax-CopyLen+Length] is set to
530   // a null character.
531   //
532   Destination = Destination + DestLen;
533   while ((*Source != 0) && (SourceLen > 0)) {
534     *(Destination++) = *(Source++);
535     SourceLen--;
536   }
537   *Destination = 0;
538 
539   return RETURN_SUCCESS;
540 }
541 
542 /**
543   Returns the length of a Null-terminated Ascii string.
544 
545   This function is similar as strlen_s defined in C11.
546 
547   @param  String   A pointer to a Null-terminated Ascii string.
548   @param  MaxSize  The maximum number of Destination Ascii
549                    char, including terminating null char.
550 
551   @retval 0        If String is NULL.
552   @retval MaxSize  If there is no null character in the first MaxSize characters of String.
553   @return The number of characters that percede the terminating null character.
554 
555 **/
556 UINTN
557 EFIAPI
AsciiStrnLenS(IN CONST CHAR8 * String,IN UINTN MaxSize)558 AsciiStrnLenS (
559   IN CONST CHAR8               *String,
560   IN UINTN                     MaxSize
561   )
562 {
563   UINTN                             Length;
564 
565   //
566   // If String is a null pointer, then the AsciiStrnLenS function returns zero.
567   //
568   if (String == NULL) {
569     return 0;
570   }
571 
572   //
573   // Otherwise, the AsciiStrnLenS function returns the number of characters that precede the
574   // terminating null character. If there is no null character in the first MaxSize characters of
575   // String then AsciiStrnLenS returns MaxSize. At most the first MaxSize characters of String shall
576   // be accessed by AsciiStrnLenS.
577   //
578   Length = 0;
579   while (String[Length] != 0) {
580     if (Length >= MaxSize - 1) {
581       return MaxSize;
582     }
583     Length++;
584   }
585   return Length;
586 }
587 
588 /**
589   Copies the string pointed to by Source (including the terminating null char)
590   to the array pointed to by Destination.
591 
592   This function is similar as strcpy_s defined in C11.
593 
594   If an error would be returned, then the function will also ASSERT().
595 
596   If an error is returned, then the Destination is unmodified.
597 
598   @param  Destination              A pointer to a Null-terminated Ascii string.
599   @param  DestMax                  The maximum number of Destination Ascii
600                                    char, including terminating null char.
601   @param  Source                   A pointer to a Null-terminated Ascii string.
602 
603   @retval RETURN_SUCCESS           String is copied.
604   @retval RETURN_BUFFER_TOO_SMALL  If DestMax is NOT greater than StrLen(Source).
605   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
606                                    If Source is NULL.
607                                    If PcdMaximumAsciiStringLength is not zero,
608                                     and DestMax is greater than
609                                     PcdMaximumAsciiStringLength.
610                                    If DestMax is 0.
611   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
612 **/
613 RETURN_STATUS
614 EFIAPI
AsciiStrCpyS(OUT CHAR8 * Destination,IN UINTN DestMax,IN CONST CHAR8 * Source)615 AsciiStrCpyS (
616   OUT CHAR8        *Destination,
617   IN  UINTN        DestMax,
618   IN  CONST CHAR8  *Source
619   )
620 {
621   UINTN            SourceLen;
622 
623   //
624   // 1. Neither Destination nor Source shall be a null pointer.
625   //
626   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
627   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
628 
629   //
630   // 2. DestMax shall not be greater than ASCII_RSIZE_MAX.
631   //
632   if (ASCII_RSIZE_MAX != 0) {
633     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
634   }
635 
636   //
637   // 3. DestMax shall not equal zero.
638   //
639   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
640 
641   //
642   // 4. DestMax shall be greater than AsciiStrnLenS(Source, DestMax).
643   //
644   SourceLen = AsciiStrnLenS (Source, DestMax);
645   SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);
646 
647   //
648   // 5. Copying shall not take place between objects that overlap.
649   //
650   SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoAsciiStrOverlap (Destination, DestMax, (CHAR8 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
651 
652   //
653   // The AsciiStrCpyS function copies the string pointed to by Source (including the terminating
654   // null character) into the array pointed to by Destination.
655   //
656   while (*Source != 0) {
657     *(Destination++) = *(Source++);
658   }
659   *Destination = 0;
660 
661   return RETURN_SUCCESS;
662 }
663 
664 /**
665   Copies not more than Length successive char from the string pointed to by
666   Source to the array pointed to by Destination. If no null char is copied from
667   Source, then Destination[Length] is always set to null.
668 
669   This function is similar as strncpy_s defined in C11.
670 
671   If an error would be returned, then the function will also ASSERT().
672 
673   If an error is returned, then the Destination is unmodified.
674 
675   @param  Destination              A pointer to a Null-terminated Ascii string.
676   @param  DestMax                  The maximum number of Destination Ascii
677                                    char, including terminating null char.
678   @param  Source                   A pointer to a Null-terminated Ascii string.
679   @param  Length                   The maximum number of Ascii characters to copy.
680 
681   @retval RETURN_SUCCESS           String is copied.
682   @retval RETURN_BUFFER_TOO_SMALL  If DestMax is NOT greater than
683                                    MIN(StrLen(Source), Length).
684   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
685                                    If Source is NULL.
686                                    If PcdMaximumAsciiStringLength is not zero,
687                                     and DestMax is greater than
688                                     PcdMaximumAsciiStringLength.
689                                    If DestMax is 0.
690   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
691 **/
692 RETURN_STATUS
693 EFIAPI
AsciiStrnCpyS(OUT CHAR8 * Destination,IN UINTN DestMax,IN CONST CHAR8 * Source,IN UINTN Length)694 AsciiStrnCpyS (
695   OUT CHAR8        *Destination,
696   IN  UINTN        DestMax,
697   IN  CONST CHAR8  *Source,
698   IN  UINTN        Length
699   )
700 {
701   UINTN            SourceLen;
702 
703   //
704   // 1. Neither Destination nor Source shall be a null pointer.
705   //
706   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
707   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
708 
709   //
710   // 2. Neither DestMax nor Length shall be greater than ASCII_RSIZE_MAX
711   //
712   if (ASCII_RSIZE_MAX != 0) {
713     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
714     SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
715   }
716 
717   //
718   // 3. DestMax shall not equal zero.
719   //
720   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
721 
722   //
723   // 4. If Length is not less than DestMax, then DestMax shall be greater than AsciiStrnLenS(Source, DestMax).
724   //
725   SourceLen = AsciiStrnLenS (Source, DestMax);
726   if (Length >= DestMax) {
727     SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);
728   }
729 
730   //
731   // 5. Copying shall not take place between objects that overlap.
732   //
733   if (SourceLen > Length) {
734     SourceLen = Length;
735   }
736   SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoAsciiStrOverlap (Destination, DestMax, (CHAR8 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
737 
738   //
739   // The AsciiStrnCpyS function copies not more than Length successive characters (characters that
740   // follow a null character are not copied) from the array pointed to by Source to the array
741   // pointed to by Destination. If no null character was copied from Source, then Destination[Length] is set to a null
742   // character.
743   //
744   while ((*Source != 0) && (SourceLen > 0)) {
745     *(Destination++) = *(Source++);
746     SourceLen--;
747   }
748   *Destination = 0;
749 
750   return RETURN_SUCCESS;
751 }
752 
753 /**
754   Appends a copy of the string pointed to by Source (including the terminating
755   null char) to the end of the string pointed to by Destination.
756 
757   This function is similar as strcat_s defined in C11.
758 
759   If an error would be returned, then the function will also ASSERT().
760 
761   If an error is returned, then the Destination is unmodified.
762 
763   @param  Destination              A pointer to a Null-terminated Ascii string.
764   @param  DestMax                  The maximum number of Destination Ascii
765                                    char, including terminating null char.
766   @param  Source                   A pointer to a Null-terminated Ascii string.
767 
768   @retval RETURN_SUCCESS           String is appended.
769   @retval RETURN_BAD_BUFFER_SIZE   If DestMax is NOT greater than
770                                    StrLen(Destination).
771   @retval RETURN_BUFFER_TOO_SMALL  If (DestMax - StrLen(Destination)) is NOT
772                                    greater than StrLen(Source).
773   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
774                                    If Source is NULL.
775                                    If PcdMaximumAsciiStringLength is not zero,
776                                     and DestMax is greater than
777                                     PcdMaximumAsciiStringLength.
778                                    If DestMax is 0.
779   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
780 **/
781 RETURN_STATUS
782 EFIAPI
AsciiStrCatS(IN OUT CHAR8 * Destination,IN UINTN DestMax,IN CONST CHAR8 * Source)783 AsciiStrCatS (
784   IN OUT CHAR8        *Destination,
785   IN     UINTN        DestMax,
786   IN     CONST CHAR8  *Source
787   )
788 {
789   UINTN               DestLen;
790   UINTN               CopyLen;
791   UINTN               SourceLen;
792 
793   //
794   // Let CopyLen denote the value DestMax - AsciiStrnLenS(Destination, DestMax) upon entry to AsciiStrCatS.
795   //
796   DestLen = AsciiStrnLenS (Destination, DestMax);
797   CopyLen = DestMax - DestLen;
798 
799   //
800   // 1. Neither Destination nor Source shall be a null pointer.
801   //
802   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
803   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
804 
805   //
806   // 2. DestMax shall not be greater than ASCII_RSIZE_MAX.
807   //
808   if (ASCII_RSIZE_MAX != 0) {
809     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
810   }
811 
812   //
813   // 3. DestMax shall not equal zero.
814   //
815   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
816 
817   //
818   // 4. CopyLen shall not equal zero.
819   //
820   SAFE_STRING_CONSTRAINT_CHECK ((CopyLen != 0), RETURN_BAD_BUFFER_SIZE);
821 
822   //
823   // 5. CopyLen shall be greater than AsciiStrnLenS(Source, CopyLen).
824   //
825   SourceLen = AsciiStrnLenS (Source, CopyLen);
826   SAFE_STRING_CONSTRAINT_CHECK ((CopyLen > SourceLen), RETURN_BUFFER_TOO_SMALL);
827 
828   //
829   // 6. Copying shall not take place between objects that overlap.
830   //
831   SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoAsciiStrOverlap (Destination, DestMax, (CHAR8 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
832 
833   //
834   // The AsciiStrCatS function appends a copy of the string pointed to by Source (including the
835   // terminating null character) to the end of the string pointed to by Destination. The initial character
836   // from Source overwrites the null character at the end of Destination.
837   //
838   Destination = Destination + DestLen;
839   while (*Source != 0) {
840     *(Destination++) = *(Source++);
841   }
842   *Destination = 0;
843 
844   return RETURN_SUCCESS;
845 }
846 
847 /**
848   Appends not more than Length successive char from the string pointed to by
849   Source to the end of the string pointed to by Destination. If no null char is
850   copied from Source, then Destination[StrLen(Destination) + Length] is always
851   set to null.
852 
853   This function is similar as strncat_s defined in C11.
854 
855   If an error would be returned, then the function will also ASSERT().
856 
857   If an error is returned, then the Destination is unmodified.
858 
859   @param  Destination              A pointer to a Null-terminated Ascii string.
860   @param  DestMax                  The maximum number of Destination Ascii
861                                    char, including terminating null char.
862   @param  Source                   A pointer to a Null-terminated Ascii string.
863   @param  Length                   The maximum number of Ascii characters to copy.
864 
865   @retval RETURN_SUCCESS           String is appended.
866   @retval RETURN_BAD_BUFFER_SIZE   If DestMax is NOT greater than
867                                    StrLen(Destination).
868   @retval RETURN_BUFFER_TOO_SMALL  If (DestMax - StrLen(Destination)) is NOT
869                                    greater than MIN(StrLen(Source), Length).
870   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
871                                    If Source is NULL.
872                                    If PcdMaximumAsciiStringLength is not zero,
873                                     and DestMax is greater than
874                                     PcdMaximumAsciiStringLength.
875                                    If DestMax is 0.
876   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
877 **/
878 RETURN_STATUS
879 EFIAPI
AsciiStrnCatS(IN OUT CHAR8 * Destination,IN UINTN DestMax,IN CONST CHAR8 * Source,IN UINTN Length)880 AsciiStrnCatS (
881   IN OUT CHAR8        *Destination,
882   IN     UINTN        DestMax,
883   IN     CONST CHAR8  *Source,
884   IN     UINTN        Length
885   )
886 {
887   UINTN               DestLen;
888   UINTN               CopyLen;
889   UINTN               SourceLen;
890 
891   //
892   // Let CopyLen denote the value DestMax - AsciiStrnLenS(Destination, DestMax) upon entry to AsciiStrnCatS.
893   //
894   DestLen = AsciiStrnLenS (Destination, DestMax);
895   CopyLen = DestMax - DestLen;
896 
897   //
898   // 1. Neither Destination nor Source shall be a null pointer.
899   //
900   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
901   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
902 
903   //
904   // 2. Neither DestMax nor Length shall be greater than ASCII_RSIZE_MAX.
905   //
906   if (ASCII_RSIZE_MAX != 0) {
907     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
908     SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
909   }
910 
911   //
912   // 3. DestMax shall not equal zero.
913   //
914   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
915 
916   //
917   // 4. CopyLen shall not equal zero.
918   //
919   SAFE_STRING_CONSTRAINT_CHECK ((CopyLen != 0), RETURN_BAD_BUFFER_SIZE);
920 
921   //
922   // 5. If Length is not less than CopyLen, then CopyLen shall be greater than AsciiStrnLenS(Source, CopyLen).
923   //
924   SourceLen = AsciiStrnLenS (Source, CopyLen);
925   if (Length >= CopyLen) {
926     SAFE_STRING_CONSTRAINT_CHECK ((CopyLen > SourceLen), RETURN_BUFFER_TOO_SMALL);
927   }
928 
929   //
930   // 6. Copying shall not take place between objects that overlap.
931   //
932   if (SourceLen > Length) {
933     SourceLen = Length;
934   }
935   SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoAsciiStrOverlap (Destination, DestMax, (CHAR8 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
936 
937   //
938   // The AsciiStrnCatS function appends not more than Length successive characters (characters
939   // that follow a null character are not copied) from the array pointed to by Source to the end of
940   // the string pointed to by Destination. The initial character from Source overwrites the null character at
941   // the end of Destination. If no null character was copied from Source, then Destination[DestMax-CopyLen+Length] is set to
942   // a null character.
943   //
944   Destination = Destination + DestLen;
945   while ((*Source != 0) && (SourceLen > 0)) {
946     *(Destination++) = *(Source++);
947     SourceLen--;
948   }
949   *Destination = 0;
950 
951   return RETURN_SUCCESS;
952 }
953 
954 /**
955   Convert a Null-terminated Unicode string to a Null-terminated
956   ASCII string.
957 
958   This function is similar to AsciiStrCpyS.
959 
960   This function converts the content of the Unicode string Source
961   to the ASCII string Destination by copying the lower 8 bits of
962   each Unicode character. The function terminates the ASCII string
963   Destination by appending a Null-terminator character at the end.
964 
965   The caller is responsible to make sure Destination points to a buffer with size
966   equal or greater than ((StrLen (Source) + 1) * sizeof (CHAR8)) in bytes.
967 
968   If any Unicode characters in Source contain non-zero value in
969   the upper 8 bits, then ASSERT().
970 
971   If Source is not aligned on a 16-bit boundary, then ASSERT().
972   If an error would be returned, then the function will also ASSERT().
973 
974   If an error is returned, then the Destination is unmodified.
975 
976   @param  Source        The pointer to a Null-terminated Unicode string.
977   @param  Destination   The pointer to a Null-terminated ASCII string.
978   @param  DestMax       The maximum number of Destination Ascii
979                         char, including terminating null char.
980 
981   @retval RETURN_SUCCESS           String is converted.
982   @retval RETURN_BUFFER_TOO_SMALL  If DestMax is NOT greater than StrLen(Source).
983   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
984                                    If Source is NULL.
985                                    If PcdMaximumAsciiStringLength is not zero,
986                                     and DestMax is greater than
987                                     PcdMaximumAsciiStringLength.
988                                    If PcdMaximumUnicodeStringLength is not zero,
989                                     and DestMax is greater than
990                                     PcdMaximumUnicodeStringLength.
991                                    If DestMax is 0.
992   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
993 
994 **/
995 RETURN_STATUS
996 EFIAPI
UnicodeStrToAsciiStrS(IN CONST CHAR16 * Source,OUT CHAR8 * Destination,IN UINTN DestMax)997 UnicodeStrToAsciiStrS (
998   IN      CONST CHAR16              *Source,
999   OUT     CHAR8                     *Destination,
1000   IN      UINTN                     DestMax
1001   )
1002 {
1003   UINTN            SourceLen;
1004 
1005   ASSERT (((UINTN) Source & BIT0) == 0);
1006 
1007   //
1008   // 1. Neither Destination nor Source shall be a null pointer.
1009   //
1010   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
1011   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
1012 
1013   //
1014   // 2. DestMax shall not be greater than ASCII_RSIZE_MAX or RSIZE_MAX.
1015   //
1016   if (ASCII_RSIZE_MAX != 0) {
1017     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
1018   }
1019   if (RSIZE_MAX != 0) {
1020     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
1021   }
1022 
1023   //
1024   // 3. DestMax shall not equal zero.
1025   //
1026   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
1027 
1028   //
1029   // 4. DestMax shall be greater than StrnLenS (Source, DestMax).
1030   //
1031   SourceLen = StrnLenS (Source, DestMax);
1032   SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);
1033 
1034   //
1035   // 5. Copying shall not take place between objects that overlap.
1036   //
1037   SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof(CHAR16)), RETURN_ACCESS_DENIED);
1038 
1039   //
1040   // convert string
1041   //
1042   while (*Source != '\0') {
1043     //
1044     // If any Unicode characters in Source contain
1045     // non-zero value in the upper 8 bits, then ASSERT().
1046     //
1047     ASSERT (*Source < 0x100);
1048     *(Destination++) = (CHAR8) *(Source++);
1049   }
1050   *Destination = '\0';
1051 
1052   return RETURN_SUCCESS;
1053 }
1054 
1055 
1056 /**
1057   Convert one Null-terminated ASCII string to a Null-terminated
1058   Unicode string.
1059 
1060   This function is similar to StrCpyS.
1061 
1062   This function converts the contents of the ASCII string Source to the Unicode
1063   string Destination. The function terminates the Unicode string Destination by
1064   appending a Null-terminator character at the end.
1065 
1066   The caller is responsible to make sure Destination points to a buffer with size
1067   equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
1068 
1069   If Destination is not aligned on a 16-bit boundary, then ASSERT().
1070   If an error would be returned, then the function will also ASSERT().
1071 
1072   If an error is returned, then the Destination is unmodified.
1073 
1074   @param  Source        The pointer to a Null-terminated ASCII string.
1075   @param  Destination   The pointer to a Null-terminated Unicode string.
1076   @param  DestMax       The maximum number of Destination Unicode
1077                         char, including terminating null char.
1078 
1079   @retval RETURN_SUCCESS           String is converted.
1080   @retval RETURN_BUFFER_TOO_SMALL  If DestMax is NOT greater than StrLen(Source).
1081   @retval RETURN_INVALID_PARAMETER If Destination is NULL.
1082                                    If Source is NULL.
1083                                    If PcdMaximumUnicodeStringLength is not zero,
1084                                     and DestMax is greater than
1085                                     PcdMaximumUnicodeStringLength.
1086                                    If PcdMaximumAsciiStringLength is not zero,
1087                                     and DestMax is greater than
1088                                     PcdMaximumAsciiStringLength.
1089                                    If DestMax is 0.
1090   @retval RETURN_ACCESS_DENIED     If Source and Destination overlap.
1091 
1092 **/
1093 RETURN_STATUS
1094 EFIAPI
AsciiStrToUnicodeStrS(IN CONST CHAR8 * Source,OUT CHAR16 * Destination,IN UINTN DestMax)1095 AsciiStrToUnicodeStrS (
1096   IN      CONST CHAR8               *Source,
1097   OUT     CHAR16                    *Destination,
1098   IN      UINTN                     DestMax
1099   )
1100 {
1101   UINTN            SourceLen;
1102 
1103   ASSERT (((UINTN) Destination & BIT0) == 0);
1104 
1105   //
1106   // 1. Neither Destination nor Source shall be a null pointer.
1107   //
1108   SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
1109   SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
1110 
1111   //
1112   // 2. DestMax shall not be greater than RSIZE_MAX or ASCII_RSIZE_MAX.
1113   //
1114   if (RSIZE_MAX != 0) {
1115     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
1116   }
1117   if (ASCII_RSIZE_MAX != 0) {
1118     SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
1119   }
1120 
1121   //
1122   // 3. DestMax shall not equal zero.
1123   //
1124   SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
1125 
1126   //
1127   // 4. DestMax shall be greater than AsciiStrnLenS(Source, DestMax).
1128   //
1129   SourceLen = AsciiStrnLenS (Source, DestMax);
1130   SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);
1131 
1132   //
1133   // 5. Copying shall not take place between objects that overlap.
1134   //
1135   SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax * sizeof(CHAR16), (VOID *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
1136 
1137   //
1138   // Convert string
1139   //
1140   while (*Source != '\0') {
1141     *(Destination++) = (CHAR16)*(Source++);
1142   }
1143   *Destination = '\0';
1144 
1145   return RETURN_SUCCESS;
1146 }
1147