]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssl/crypto/bio/b_print.c
Merge llvm-project release/16.x llvmorg-16.0.4-0-gae42196bc493
[FreeBSD/FreeBSD.git] / crypto / openssl / crypto / bio / b_print.c
1 /*
2  * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include "internal/cryptlib.h"
13 #include "crypto/ctype.h"
14 #include "internal/numbers.h"
15 #include <openssl/bio.h>
16 #include <openssl/opensslconf.h>
17
18 /*
19  * Copyright Patrick Powell 1995
20  * This code is based on code written by Patrick Powell <papowell@astart.com>
21  * It may be used for any purpose as long as this notice remains intact
22  * on all source code distributions.
23  */
24
25 #ifdef HAVE_LONG_DOUBLE
26 # define LDOUBLE long double
27 #else
28 # define LDOUBLE double
29 #endif
30
31 static int fmtstr(char **, char **, size_t *, size_t *,
32                   const char *, int, int, int);
33 static int fmtint(char **, char **, size_t *, size_t *,
34                   int64_t, int, int, int, int);
35 #ifndef OPENSSL_SYS_UEFI
36 static int fmtfp(char **, char **, size_t *, size_t *,
37                  LDOUBLE, int, int, int, int);
38 #endif
39 static int doapr_outch(char **, char **, size_t *, size_t *, int);
40 static int _dopr(char **sbuffer, char **buffer,
41                  size_t *maxlen, size_t *retlen, int *truncated,
42                  const char *format, va_list args);
43
44 /* format read states */
45 #define DP_S_DEFAULT    0
46 #define DP_S_FLAGS      1
47 #define DP_S_MIN        2
48 #define DP_S_DOT        3
49 #define DP_S_MAX        4
50 #define DP_S_MOD        5
51 #define DP_S_CONV       6
52 #define DP_S_DONE       7
53
54 /* format flags - Bits */
55 /* left-aligned padding */
56 #define DP_F_MINUS      (1 << 0)
57 /* print an explicit '+' for a value with positive sign */
58 #define DP_F_PLUS       (1 << 1)
59 /* print an explicit ' ' for a value with positive sign */
60 #define DP_F_SPACE      (1 << 2)
61 /* print 0/0x prefix for octal/hex and decimal point for floating point */
62 #define DP_F_NUM        (1 << 3)
63 /* print leading zeroes */
64 #define DP_F_ZERO       (1 << 4)
65 /* print HEX in UPPPERcase */
66 #define DP_F_UP         (1 << 5)
67 /* treat value as unsigned */
68 #define DP_F_UNSIGNED   (1 << 6)
69
70 /* conversion flags */
71 #define DP_C_SHORT      1
72 #define DP_C_LONG       2
73 #define DP_C_LDOUBLE    3
74 #define DP_C_LLONG      4
75 #define DP_C_SIZE       5
76
77 /* Floating point formats */
78 #define F_FORMAT        0
79 #define E_FORMAT        1
80 #define G_FORMAT        2
81
82 /* some handy macros */
83 #define char_to_int(p) (p - '0')
84 #define OSSL_MAX(p,q) ((p >= q) ? p : q)
85
86 static int
87 _dopr(char **sbuffer,
88       char **buffer,
89       size_t *maxlen,
90       size_t *retlen, int *truncated, const char *format, va_list args)
91 {
92     char ch;
93     int64_t value;
94 #ifndef OPENSSL_SYS_UEFI
95     LDOUBLE fvalue;
96 #endif
97     char *strvalue;
98     int min;
99     int max;
100     int state;
101     int flags;
102     int cflags;
103     size_t currlen;
104
105     state = DP_S_DEFAULT;
106     flags = currlen = cflags = min = 0;
107     max = -1;
108     ch = *format++;
109
110     while (state != DP_S_DONE) {
111         if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
112             state = DP_S_DONE;
113
114         switch (state) {
115         case DP_S_DEFAULT:
116             if (ch == '%')
117                 state = DP_S_FLAGS;
118             else
119                 if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
120                     return 0;
121             ch = *format++;
122             break;
123         case DP_S_FLAGS:
124             switch (ch) {
125             case '-':
126                 flags |= DP_F_MINUS;
127                 ch = *format++;
128                 break;
129             case '+':
130                 flags |= DP_F_PLUS;
131                 ch = *format++;
132                 break;
133             case ' ':
134                 flags |= DP_F_SPACE;
135                 ch = *format++;
136                 break;
137             case '#':
138                 flags |= DP_F_NUM;
139                 ch = *format++;
140                 break;
141             case '0':
142                 flags |= DP_F_ZERO;
143                 ch = *format++;
144                 break;
145             default:
146                 state = DP_S_MIN;
147                 break;
148             }
149             break;
150         case DP_S_MIN:
151             if (ossl_isdigit(ch)) {
152                 min = 10 * min + char_to_int(ch);
153                 ch = *format++;
154             } else if (ch == '*') {
155                 min = va_arg(args, int);
156                 ch = *format++;
157                 state = DP_S_DOT;
158             } else
159                 state = DP_S_DOT;
160             break;
161         case DP_S_DOT:
162             if (ch == '.') {
163                 state = DP_S_MAX;
164                 ch = *format++;
165             } else
166                 state = DP_S_MOD;
167             break;
168         case DP_S_MAX:
169             if (ossl_isdigit(ch)) {
170                 if (max < 0)
171                     max = 0;
172                 max = 10 * max + char_to_int(ch);
173                 ch = *format++;
174             } else if (ch == '*') {
175                 max = va_arg(args, int);
176                 ch = *format++;
177                 state = DP_S_MOD;
178             } else
179                 state = DP_S_MOD;
180             break;
181         case DP_S_MOD:
182             switch (ch) {
183             case 'h':
184                 cflags = DP_C_SHORT;
185                 ch = *format++;
186                 break;
187             case 'l':
188                 if (*format == 'l') {
189                     cflags = DP_C_LLONG;
190                     format++;
191                 } else
192                     cflags = DP_C_LONG;
193                 ch = *format++;
194                 break;
195             case 'q':
196             case 'j':
197                 cflags = DP_C_LLONG;
198                 ch = *format++;
199                 break;
200             case 'L':
201                 cflags = DP_C_LDOUBLE;
202                 ch = *format++;
203                 break;
204             case 'z':
205                 cflags = DP_C_SIZE;
206                 ch = *format++;
207                 break;
208             default:
209                 break;
210             }
211             state = DP_S_CONV;
212             break;
213         case DP_S_CONV:
214             switch (ch) {
215             case 'd':
216             case 'i':
217                 switch (cflags) {
218                 case DP_C_SHORT:
219                     value = (short int)va_arg(args, int);
220                     break;
221                 case DP_C_LONG:
222                     value = va_arg(args, long int);
223                     break;
224                 case DP_C_LLONG:
225                     value = va_arg(args, int64_t);
226                     break;
227                 case DP_C_SIZE:
228                     value = va_arg(args, ossl_ssize_t);
229                     break;
230                 default:
231                     value = va_arg(args, int);
232                     break;
233                 }
234                 if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
235                             max, flags))
236                     return 0;
237                 break;
238             case 'X':
239                 flags |= DP_F_UP;
240                 /* FALLTHROUGH */
241             case 'x':
242             case 'o':
243             case 'u':
244                 flags |= DP_F_UNSIGNED;
245                 switch (cflags) {
246                 case DP_C_SHORT:
247                     value = (unsigned short int)va_arg(args, unsigned int);
248                     break;
249                 case DP_C_LONG:
250                     value = va_arg(args, unsigned long int);
251                     break;
252                 case DP_C_LLONG:
253                     value = va_arg(args, uint64_t);
254                     break;
255                 case DP_C_SIZE:
256                     value = va_arg(args, size_t);
257                     break;
258                 default:
259                     value = va_arg(args, unsigned int);
260                     break;
261                 }
262                 if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
263                             ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
264                             min, max, flags))
265                     return 0;
266                 break;
267 #ifndef OPENSSL_SYS_UEFI
268             case 'f':
269                 if (cflags == DP_C_LDOUBLE)
270                     fvalue = va_arg(args, LDOUBLE);
271                 else
272                     fvalue = va_arg(args, double);
273                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
274                            flags, F_FORMAT))
275                     return 0;
276                 break;
277             case 'E':
278                 flags |= DP_F_UP;
279                 /* fall thru */
280             case 'e':
281                 if (cflags == DP_C_LDOUBLE)
282                     fvalue = va_arg(args, LDOUBLE);
283                 else
284                     fvalue = va_arg(args, double);
285                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
286                            flags, E_FORMAT))
287                     return 0;
288                 break;
289             case 'G':
290                 flags |= DP_F_UP;
291                 /* fall thru */
292             case 'g':
293                 if (cflags == DP_C_LDOUBLE)
294                     fvalue = va_arg(args, LDOUBLE);
295                 else
296                     fvalue = va_arg(args, double);
297                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
298                            flags, G_FORMAT))
299                     return 0;
300                 break;
301 #else
302             case 'f':
303             case 'E':
304             case 'e':
305             case 'G':
306             case 'g':
307                 /* not implemented for UEFI */
308                 return 0;
309 #endif
310             case 'c':
311                 if (!doapr_outch(sbuffer, buffer, &currlen, maxlen,
312                                  va_arg(args, int)))
313                     return 0;
314                 break;
315             case 's':
316                 strvalue = va_arg(args, char *);
317                 if (max < 0) {
318                     if (buffer)
319                         max = INT_MAX;
320                     else
321                         max = *maxlen;
322                 }
323                 if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
324                             flags, min, max))
325                     return 0;
326                 break;
327             case 'p':
328                 value = (size_t)va_arg(args, void *);
329                 if (!fmtint(sbuffer, buffer, &currlen, maxlen,
330                             value, 16, min, max, flags | DP_F_NUM))
331                     return 0;
332                 break;
333             case 'n':
334                 {
335                     int *num;
336                     num = va_arg(args, int *);
337                     *num = currlen;
338                 }
339                 break;
340             case '%':
341                 if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
342                     return 0;
343                 break;
344             case 'w':
345                 /* not supported yet, treat as next char */
346                 ch = *format++;
347                 break;
348             default:
349                 /* unknown, skip */
350                 break;
351             }
352             ch = *format++;
353             state = DP_S_DEFAULT;
354             flags = cflags = min = 0;
355             max = -1;
356             break;
357         case DP_S_DONE:
358             break;
359         default:
360             break;
361         }
362     }
363     /*
364      * We have to truncate if there is no dynamic buffer and we have filled the
365      * static buffer.
366      */
367     if (buffer == NULL) {
368         *truncated = (currlen > *maxlen - 1);
369         if (*truncated)
370             currlen = *maxlen - 1;
371     }
372     if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
373         return 0;
374     *retlen = currlen - 1;
375     return 1;
376 }
377
378 static int
379 fmtstr(char **sbuffer,
380        char **buffer,
381        size_t *currlen,
382        size_t *maxlen, const char *value, int flags, int min, int max)
383 {
384     int padlen;
385     size_t strln;
386     int cnt = 0;
387
388     if (value == 0)
389         value = "<NULL>";
390
391     strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max);
392
393     padlen = min - strln;
394     if (min < 0 || padlen < 0)
395         padlen = 0;
396     if (max >= 0) {
397         /*
398          * Calculate the maximum output including padding.
399          * Make sure max doesn't overflow into negativity
400          */
401         if (max < INT_MAX - padlen)
402             max += padlen;
403         else
404             max = INT_MAX;
405     }
406     if (flags & DP_F_MINUS)
407         padlen = -padlen;
408
409     while ((padlen > 0) && (max < 0 || cnt < max)) {
410         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
411             return 0;
412         --padlen;
413         ++cnt;
414     }
415     while (strln > 0 && (max < 0 || cnt < max)) {
416         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
417             return 0;
418         --strln;
419         ++cnt;
420     }
421     while ((padlen < 0) && (max < 0 || cnt < max)) {
422         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
423             return 0;
424         ++padlen;
425         ++cnt;
426     }
427     return 1;
428 }
429
430 static int
431 fmtint(char **sbuffer,
432        char **buffer,
433        size_t *currlen,
434        size_t *maxlen, int64_t value, int base, int min, int max, int flags)
435 {
436     int signvalue = 0;
437     const char *prefix = "";
438     uint64_t uvalue;
439     char convert[DECIMAL_SIZE(value) + 3];
440     int place = 0;
441     int spadlen = 0;
442     int zpadlen = 0;
443     int caps = 0;
444
445     if (max < 0)
446         max = 0;
447     uvalue = value;
448     if (!(flags & DP_F_UNSIGNED)) {
449         if (value < 0) {
450             signvalue = '-';
451             uvalue = 0 - (uint64_t)value;
452         } else if (flags & DP_F_PLUS)
453             signvalue = '+';
454         else if (flags & DP_F_SPACE)
455             signvalue = ' ';
456     }
457     if (flags & DP_F_NUM) {
458         if (base == 8)
459             prefix = "0";
460         if (base == 16)
461             prefix = "0x";
462     }
463     if (flags & DP_F_UP)
464         caps = 1;
465     do {
466         convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
467             [uvalue % (unsigned)base];
468         uvalue = (uvalue / (unsigned)base);
469     } while (uvalue && (place < (int)sizeof(convert)));
470     if (place == sizeof(convert))
471         place--;
472     convert[place] = 0;
473
474     zpadlen = max - place;
475     spadlen =
476         min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
477     if (zpadlen < 0)
478         zpadlen = 0;
479     if (spadlen < 0)
480         spadlen = 0;
481     if (flags & DP_F_ZERO) {
482         zpadlen = OSSL_MAX(zpadlen, spadlen);
483         spadlen = 0;
484     }
485     if (flags & DP_F_MINUS)
486         spadlen = -spadlen;
487
488     /* spaces */
489     while (spadlen > 0) {
490         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
491             return 0;
492         --spadlen;
493     }
494
495     /* sign */
496     if (signvalue)
497         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
498             return 0;
499
500     /* prefix */
501     while (*prefix) {
502         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
503             return 0;
504         prefix++;
505     }
506
507     /* zeros */
508     if (zpadlen > 0) {
509         while (zpadlen > 0) {
510             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
511                 return 0;
512             --zpadlen;
513         }
514     }
515     /* digits */
516     while (place > 0) {
517         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
518             return 0;
519     }
520
521     /* left justified spaces */
522     while (spadlen < 0) {
523         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
524             return 0;
525         ++spadlen;
526     }
527     return 1;
528 }
529
530 #ifndef OPENSSL_SYS_UEFI
531
532 static LDOUBLE abs_val(LDOUBLE value)
533 {
534     LDOUBLE result = value;
535     if (value < 0)
536         result = -value;
537     return result;
538 }
539
540 static LDOUBLE pow_10(int in_exp)
541 {
542     LDOUBLE result = 1;
543     while (in_exp) {
544         result *= 10;
545         in_exp--;
546     }
547     return result;
548 }
549
550 static long roundv(LDOUBLE value)
551 {
552     long intpart;
553     intpart = (long)value;
554     value = value - intpart;
555     if (value >= 0.5)
556         intpart++;
557     return intpart;
558 }
559
560 static int
561 fmtfp(char **sbuffer,
562       char **buffer,
563       size_t *currlen,
564       size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style)
565 {
566     int signvalue = 0;
567     LDOUBLE ufvalue;
568     LDOUBLE tmpvalue;
569     char iconvert[20];
570     char fconvert[20];
571     char econvert[20];
572     int iplace = 0;
573     int fplace = 0;
574     int eplace = 0;
575     int padlen = 0;
576     int zpadlen = 0;
577     long exp = 0;
578     unsigned long intpart;
579     unsigned long fracpart;
580     unsigned long max10;
581     int realstyle;
582
583     if (max < 0)
584         max = 6;
585
586     if (fvalue < 0)
587         signvalue = '-';
588     else if (flags & DP_F_PLUS)
589         signvalue = '+';
590     else if (flags & DP_F_SPACE)
591         signvalue = ' ';
592
593     /*
594      * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT
595      * depending on the number to be printed. Work out which one it is and use
596      * that from here on.
597      */
598     if (style == G_FORMAT) {
599         if (fvalue == 0.0) {
600             realstyle = F_FORMAT;
601         } else if (fvalue < 0.0001) {
602             realstyle = E_FORMAT;
603         } else if ((max == 0 && fvalue >= 10)
604                     || (max > 0 && fvalue >= pow_10(max))) {
605             realstyle = E_FORMAT;
606         } else {
607             realstyle = F_FORMAT;
608         }
609     } else {
610         realstyle = style;
611     }
612
613     if (style != F_FORMAT) {
614         tmpvalue = fvalue;
615         /* Calculate the exponent */
616         if (fvalue != 0.0) {
617             while (tmpvalue < 1) {
618                 tmpvalue *= 10;
619                 exp--;
620             }
621             while (tmpvalue > 10) {
622                 tmpvalue /= 10;
623                 exp++;
624             }
625         }
626         if (style == G_FORMAT) {
627             /*
628              * In G_FORMAT the "precision" represents significant digits. We
629              * always have at least 1 significant digit.
630              */
631             if (max == 0)
632                 max = 1;
633             /* Now convert significant digits to decimal places */
634             if (realstyle == F_FORMAT) {
635                 max -= (exp + 1);
636                 if (max < 0) {
637                     /*
638                      * Should not happen. If we're in F_FORMAT then exp < max?
639                      */
640                     return 0;
641                 }
642             } else {
643                 /*
644                  * In E_FORMAT there is always one significant digit in front
645                  * of the decimal point, so:
646                  * significant digits == 1 + decimal places
647                  */
648                 max--;
649             }
650         }
651         if (realstyle == E_FORMAT)
652             fvalue = tmpvalue;
653     }
654     ufvalue = abs_val(fvalue);
655     /*
656      * By subtracting 65535 (2^16-1) we cancel the low order 15 bits
657      * of ULONG_MAX to avoid using imprecise floating point values.
658      */
659     if (ufvalue >= (double)(ULONG_MAX - 65535) + 65536.0) {
660         /* Number too big */
661         return 0;
662     }
663     intpart = (unsigned long)ufvalue;
664
665     /*
666      * sorry, we only support 9 digits past the decimal because of our
667      * conversion method
668      */
669     if (max > 9)
670         max = 9;
671
672     /*
673      * we "cheat" by converting the fractional part to integer by multiplying
674      * by a factor of 10
675      */
676     max10 = roundv(pow_10(max));
677     fracpart = roundv(pow_10(max) * (ufvalue - intpart));
678
679     if (fracpart >= max10) {
680         intpart++;
681         fracpart -= max10;
682     }
683
684     /* convert integer part */
685     do {
686         iconvert[iplace++] = "0123456789"[intpart % 10];
687         intpart = (intpart / 10);
688     } while (intpart && (iplace < (int)sizeof(iconvert)));
689     if (iplace == sizeof(iconvert))
690         iplace--;
691     iconvert[iplace] = 0;
692
693     /* convert fractional part */
694     while (fplace < max) {
695         if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) {
696             /* We strip trailing zeros in G_FORMAT */
697             max--;
698             fracpart = fracpart / 10;
699             if (fplace < max)
700                 continue;
701             break;
702         }
703         fconvert[fplace++] = "0123456789"[fracpart % 10];
704         fracpart = (fracpart / 10);
705     }
706
707     if (fplace == sizeof(fconvert))
708         fplace--;
709     fconvert[fplace] = 0;
710
711     /* convert exponent part */
712     if (realstyle == E_FORMAT) {
713         int tmpexp;
714         if (exp < 0)
715             tmpexp = -exp;
716         else
717             tmpexp = exp;
718
719         do {
720             econvert[eplace++] = "0123456789"[tmpexp % 10];
721             tmpexp = (tmpexp / 10);
722         } while (tmpexp > 0 && eplace < (int)sizeof(econvert));
723         /* Exponent is huge!! Too big to print */
724         if (tmpexp > 0)
725             return 0;
726         /* Add a leading 0 for single digit exponents */
727         if (eplace == 1)
728             econvert[eplace++] = '0';
729     }
730
731     /*
732      * -1 for decimal point (if we have one, i.e. max > 0),
733      * another -1 if we are printing a sign
734      */
735     padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0);
736     /* Take some off for exponent prefix "+e" and exponent */
737     if (realstyle == E_FORMAT)
738         padlen -= 2 + eplace;
739     zpadlen = max - fplace;
740     if (zpadlen < 0)
741         zpadlen = 0;
742     if (padlen < 0)
743         padlen = 0;
744     if (flags & DP_F_MINUS)
745         padlen = -padlen;
746
747     if ((flags & DP_F_ZERO) && (padlen > 0)) {
748         if (signvalue) {
749             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
750                 return 0;
751             --padlen;
752             signvalue = 0;
753         }
754         while (padlen > 0) {
755             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
756                 return 0;
757             --padlen;
758         }
759     }
760     while (padlen > 0) {
761         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
762             return 0;
763         --padlen;
764     }
765     if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
766         return 0;
767
768     while (iplace > 0) {
769         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
770             return 0;
771     }
772
773     /*
774      * Decimal point. This should probably use locale to find the correct
775      * char to print out.
776      */
777     if (max > 0 || (flags & DP_F_NUM)) {
778         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
779             return 0;
780
781         while (fplace > 0) {
782             if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
783                              fconvert[--fplace]))
784                 return 0;
785         }
786     }
787     while (zpadlen > 0) {
788         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
789             return 0;
790         --zpadlen;
791     }
792     if (realstyle == E_FORMAT) {
793         char ech;
794
795         if ((flags & DP_F_UP) == 0)
796             ech = 'e';
797         else
798             ech = 'E';
799         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech))
800                 return 0;
801         if (exp < 0) {
802             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-'))
803                     return 0;
804         } else {
805             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+'))
806                     return 0;
807         }
808         while (eplace > 0) {
809             if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
810                              econvert[--eplace]))
811                 return 0;
812         }
813     }
814
815     while (padlen < 0) {
816         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
817             return 0;
818         ++padlen;
819     }
820     return 1;
821 }
822
823 #endif /* OPENSSL_SYS_UEFI */
824
825 #define BUFFER_INC  1024
826
827 static int
828 doapr_outch(char **sbuffer,
829             char **buffer, size_t *currlen, size_t *maxlen, int c)
830 {
831     /* If we haven't at least one buffer, someone has done a big booboo */
832     if (!ossl_assert(*sbuffer != NULL || buffer != NULL))
833         return 0;
834
835     /* |currlen| must always be <= |*maxlen| */
836     if (!ossl_assert(*currlen <= *maxlen))
837         return 0;
838
839     if (buffer && *currlen == *maxlen) {
840         if (*maxlen > INT_MAX - BUFFER_INC)
841             return 0;
842
843         *maxlen += BUFFER_INC;
844         if (*buffer == NULL) {
845             if ((*buffer = OPENSSL_malloc(*maxlen)) == NULL) {
846                 BIOerr(BIO_F_DOAPR_OUTCH, ERR_R_MALLOC_FAILURE);
847                 return 0;
848             }
849             if (*currlen > 0) {
850                 if (!ossl_assert(*sbuffer != NULL))
851                     return 0;
852                 memcpy(*buffer, *sbuffer, *currlen);
853             }
854             *sbuffer = NULL;
855         } else {
856             char *tmpbuf;
857             tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
858             if (tmpbuf == NULL)
859                 return 0;
860             *buffer = tmpbuf;
861         }
862     }
863
864     if (*currlen < *maxlen) {
865         if (*sbuffer)
866             (*sbuffer)[(*currlen)++] = (char)c;
867         else
868             (*buffer)[(*currlen)++] = (char)c;
869     }
870
871     return 1;
872 }
873
874 /***************************************************************************/
875
876 int BIO_printf(BIO *bio, const char *format, ...)
877 {
878     va_list args;
879     int ret;
880
881     va_start(args, format);
882
883     ret = BIO_vprintf(bio, format, args);
884
885     va_end(args);
886     return ret;
887 }
888
889 int BIO_vprintf(BIO *bio, const char *format, va_list args)
890 {
891     int ret;
892     size_t retlen;
893     char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
894                                  * in small-stack environments, like threads
895                                  * or DOS programs. */
896     char *hugebufp = hugebuf;
897     size_t hugebufsize = sizeof(hugebuf);
898     char *dynbuf = NULL;
899     int ignored;
900
901     dynbuf = NULL;
902     if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
903                 args)) {
904         OPENSSL_free(dynbuf);
905         return -1;
906     }
907     if (dynbuf) {
908         ret = BIO_write(bio, dynbuf, (int)retlen);
909         OPENSSL_free(dynbuf);
910     } else {
911         ret = BIO_write(bio, hugebuf, (int)retlen);
912     }
913     return ret;
914 }
915
916 /*
917  * As snprintf is not available everywhere, we provide our own
918  * implementation. This function has nothing to do with BIOs, but it's
919  * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
920  * function should be renamed, but to what?)
921  */
922 int BIO_snprintf(char *buf, size_t n, const char *format, ...)
923 {
924     va_list args;
925     int ret;
926
927     va_start(args, format);
928
929     ret = BIO_vsnprintf(buf, n, format, args);
930
931     va_end(args);
932     return ret;
933 }
934
935 int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
936 {
937     size_t retlen;
938     int truncated;
939
940     if (!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
941         return -1;
942
943     if (truncated)
944         /*
945          * In case of truncation, return -1 like traditional snprintf.
946          * (Current drafts for ISO/IEC 9899 say snprintf should return the
947          * number of characters that would have been written, had the buffer
948          * been large enough.)
949          */
950         return -1;
951     else
952         return (retlen <= INT_MAX) ? (int)retlen : -1;
953 }