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
31static int fmtstr(char **, char **, size_t *, size_t *,
32                  const char *, int, int, int);
33static int fmtint(char **, char **, size_t *, size_t *,
34                  int64_t, int, int, int, int);
35#ifndef OPENSSL_SYS_UEFI
36static int fmtfp(char **, char **, size_t *, size_t *,
37                 LDOUBLE, int, int, int, int);
38#endif
39static int doapr_outch(char **, char **, size_t *, size_t *, int);
40static 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
86static 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                ERR_raise(ERR_LIB_BIO, ERR_R_UNSUPPORTED);
309                return 0;
310#endif
311            case 'c':
312                if (!doapr_outch(sbuffer, buffer, &currlen, maxlen,
313                                 va_arg(args, int)))
314                    return 0;
315                break;
316            case 's':
317                strvalue = va_arg(args, char *);
318                if (max < 0) {
319                    if (buffer)
320                        max = INT_MAX;
321                    else
322                        max = *maxlen;
323                }
324                if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
325                            flags, min, max))
326                    return 0;
327                break;
328            case 'p':
329                value = (size_t)va_arg(args, void *);
330                if (!fmtint(sbuffer, buffer, &currlen, maxlen,
331                            value, 16, min, max, flags | DP_F_NUM))
332                    return 0;
333                break;
334            case 'n':
335                {
336                    int *num;
337                    num = va_arg(args, int *);
338                    *num = currlen;
339                }
340                break;
341            case '%':
342                if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
343                    return 0;
344                break;
345            case 'w':
346                /* not supported yet, treat as next char */
347                ch = *format++;
348                break;
349            default:
350                /* unknown, skip */
351                break;
352            }
353            ch = *format++;
354            state = DP_S_DEFAULT;
355            flags = cflags = min = 0;
356            max = -1;
357            break;
358        case DP_S_DONE:
359            break;
360        default:
361            break;
362        }
363    }
364    /*
365     * We have to truncate if there is no dynamic buffer and we have filled the
366     * static buffer.
367     */
368    if (buffer == NULL) {
369        *truncated = (currlen > *maxlen - 1);
370        if (*truncated)
371            currlen = *maxlen - 1;
372    }
373    if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
374        return 0;
375    *retlen = currlen - 1;
376    return 1;
377}
378
379static int
380fmtstr(char **sbuffer,
381       char **buffer,
382       size_t *currlen,
383       size_t *maxlen, const char *value, int flags, int min, int max)
384{
385    int padlen;
386    size_t strln;
387    int cnt = 0;
388
389    if (value == 0)
390        value = "<NULL>";
391
392    strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max);
393
394    padlen = min - strln;
395    if (min < 0 || padlen < 0)
396        padlen = 0;
397    if (max >= 0) {
398        /*
399         * Calculate the maximum output including padding.
400         * Make sure max doesn't overflow into negativity
401         */
402        if (max < INT_MAX - padlen)
403            max += padlen;
404        else
405            max = INT_MAX;
406    }
407    if (flags & DP_F_MINUS)
408        padlen = -padlen;
409
410    while ((padlen > 0) && (max < 0 || cnt < max)) {
411        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
412            return 0;
413        --padlen;
414        ++cnt;
415    }
416    while (strln > 0 && (max < 0 || cnt < max)) {
417        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
418            return 0;
419        --strln;
420        ++cnt;
421    }
422    while ((padlen < 0) && (max < 0 || cnt < max)) {
423        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
424            return 0;
425        ++padlen;
426        ++cnt;
427    }
428    return 1;
429}
430
431static int
432fmtint(char **sbuffer,
433       char **buffer,
434       size_t *currlen,
435       size_t *maxlen, int64_t value, int base, int min, int max, int flags)
436{
437    int signvalue = 0;
438    const char *prefix = "";
439    uint64_t uvalue;
440    char convert[DECIMAL_SIZE(value) + 3];
441    int place = 0;
442    int spadlen = 0;
443    int zpadlen = 0;
444    int caps = 0;
445
446    if (max < 0)
447        max = 0;
448    uvalue = value;
449    if (!(flags & DP_F_UNSIGNED)) {
450        if (value < 0) {
451            signvalue = '-';
452            uvalue = 0 - (uint64_t)value;
453        } else if (flags & DP_F_PLUS)
454            signvalue = '+';
455        else if (flags & DP_F_SPACE)
456            signvalue = ' ';
457    }
458    if (flags & DP_F_NUM) {
459        if (base == 8)
460            prefix = "0";
461        if (base == 16)
462            prefix = "0x";
463    }
464    if (flags & DP_F_UP)
465        caps = 1;
466    do {
467        convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
468            [uvalue % (unsigned)base];
469        uvalue = (uvalue / (unsigned)base);
470    } while (uvalue && (place < (int)sizeof(convert)));
471    if (place == sizeof(convert))
472        place--;
473    convert[place] = 0;
474
475    zpadlen = max - place;
476    spadlen =
477        min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
478    if (zpadlen < 0)
479        zpadlen = 0;
480    if (spadlen < 0)
481        spadlen = 0;
482    if (flags & DP_F_ZERO) {
483        zpadlen = OSSL_MAX(zpadlen, spadlen);
484        spadlen = 0;
485    }
486    if (flags & DP_F_MINUS)
487        spadlen = -spadlen;
488
489    /* spaces */
490    while (spadlen > 0) {
491        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
492            return 0;
493        --spadlen;
494    }
495
496    /* sign */
497    if (signvalue)
498        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
499            return 0;
500
501    /* prefix */
502    while (*prefix) {
503        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
504            return 0;
505        prefix++;
506    }
507
508    /* zeros */
509    if (zpadlen > 0) {
510        while (zpadlen > 0) {
511            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
512                return 0;
513            --zpadlen;
514        }
515    }
516    /* digits */
517    while (place > 0) {
518        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
519            return 0;
520    }
521
522    /* left justified spaces */
523    while (spadlen < 0) {
524        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
525            return 0;
526        ++spadlen;
527    }
528    return 1;
529}
530
531#ifndef OPENSSL_SYS_UEFI
532
533static LDOUBLE abs_val(LDOUBLE value)
534{
535    LDOUBLE result = value;
536    if (value < 0)
537        result = -value;
538    return result;
539}
540
541static LDOUBLE pow_10(int in_exp)
542{
543    LDOUBLE result = 1;
544    while (in_exp) {
545        result *= 10;
546        in_exp--;
547    }
548    return result;
549}
550
551static long roundv(LDOUBLE value)
552{
553    long intpart;
554    intpart = (long)value;
555    value = value - intpart;
556    if (value >= 0.5)
557        intpart++;
558    return intpart;
559}
560
561static int
562fmtfp(char **sbuffer,
563      char **buffer,
564      size_t *currlen,
565      size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style)
566{
567    int signvalue = 0;
568    LDOUBLE ufvalue;
569    LDOUBLE tmpvalue;
570    char iconvert[20];
571    char fconvert[20];
572    char econvert[20];
573    int iplace = 0;
574    int fplace = 0;
575    int eplace = 0;
576    int padlen = 0;
577    int zpadlen = 0;
578    long exp = 0;
579    unsigned long intpart;
580    unsigned long fracpart;
581    unsigned long max10;
582    int realstyle;
583
584    if (max < 0)
585        max = 6;
586
587    if (fvalue < 0)
588        signvalue = '-';
589    else if (flags & DP_F_PLUS)
590        signvalue = '+';
591    else if (flags & DP_F_SPACE)
592        signvalue = ' ';
593
594    /*
595     * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT
596     * depending on the number to be printed. Work out which one it is and use
597     * that from here on.
598     */
599    if (style == G_FORMAT) {
600        if (fvalue == 0.0) {
601            realstyle = F_FORMAT;
602        } else if (fvalue < 0.0001) {
603            realstyle = E_FORMAT;
604        } else if ((max == 0 && fvalue >= 10)
605                    || (max > 0 && fvalue >= pow_10(max))) {
606            realstyle = E_FORMAT;
607        } else {
608            realstyle = F_FORMAT;
609        }
610    } else {
611        realstyle = style;
612    }
613
614    if (style != F_FORMAT) {
615        tmpvalue = fvalue;
616        /* Calculate the exponent */
617        if (fvalue != 0.0) {
618            while (tmpvalue < 1) {
619                tmpvalue *= 10;
620                exp--;
621            }
622            while (tmpvalue > 10) {
623                tmpvalue /= 10;
624                exp++;
625            }
626        }
627        if (style == G_FORMAT) {
628            /*
629             * In G_FORMAT the "precision" represents significant digits. We
630             * always have at least 1 significant digit.
631             */
632            if (max == 0)
633                max = 1;
634            /* Now convert significant digits to decimal places */
635            if (realstyle == F_FORMAT) {
636                max -= (exp + 1);
637                if (max < 0) {
638                    /*
639                     * Should not happen. If we're in F_FORMAT then exp < max?
640                     */
641                    return 0;
642                }
643            } else {
644                /*
645                 * In E_FORMAT there is always one significant digit in front
646                 * of the decimal point, so:
647                 * significant digits == 1 + decimal places
648                 */
649                max--;
650            }
651        }
652        if (realstyle == E_FORMAT)
653            fvalue = tmpvalue;
654    }
655    ufvalue = abs_val(fvalue);
656    /*
657     * By subtracting 65535 (2^16-1) we cancel the low order 15 bits
658     * of ULONG_MAX to avoid using imprecise floating point values.
659     */
660    if (ufvalue >= (double)(ULONG_MAX - 65535) + 65536.0) {
661        /* Number too big */
662        return 0;
663    }
664    intpart = (unsigned long)ufvalue;
665
666    /*
667     * sorry, we only support 9 digits past the decimal because of our
668     * conversion method
669     */
670    if (max > 9)
671        max = 9;
672
673    /*
674     * we "cheat" by converting the fractional part to integer by multiplying
675     * by a factor of 10
676     */
677    max10 = roundv(pow_10(max));
678    fracpart = roundv(pow_10(max) * (ufvalue - intpart));
679
680    if (fracpart >= max10) {
681        intpart++;
682        fracpart -= max10;
683    }
684
685    /* convert integer part */
686    do {
687        iconvert[iplace++] = "0123456789"[intpart % 10];
688        intpart = (intpart / 10);
689    } while (intpart && (iplace < (int)sizeof(iconvert)));
690    if (iplace == sizeof(iconvert))
691        iplace--;
692    iconvert[iplace] = 0;
693
694    /* convert fractional part */
695    while (fplace < max) {
696        if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) {
697            /* We strip trailing zeros in G_FORMAT */
698            max--;
699            fracpart = fracpart / 10;
700            if (fplace < max)
701                continue;
702            break;
703        }
704        fconvert[fplace++] = "0123456789"[fracpart % 10];
705        fracpart = (fracpart / 10);
706    }
707
708    if (fplace == sizeof(fconvert))
709        fplace--;
710    fconvert[fplace] = 0;
711
712    /* convert exponent part */
713    if (realstyle == E_FORMAT) {
714        int tmpexp;
715        if (exp < 0)
716            tmpexp = -exp;
717        else
718            tmpexp = exp;
719
720        do {
721            econvert[eplace++] = "0123456789"[tmpexp % 10];
722            tmpexp = (tmpexp / 10);
723        } while (tmpexp > 0 && eplace < (int)sizeof(econvert));
724        /* Exponent is huge!! Too big to print */
725        if (tmpexp > 0)
726            return 0;
727        /* Add a leading 0 for single digit exponents */
728        if (eplace == 1)
729            econvert[eplace++] = '0';
730    }
731
732    /*
733     * -1 for decimal point (if we have one, i.e. max > 0),
734     * another -1 if we are printing a sign
735     */
736    padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0);
737    /* Take some off for exponent prefix "+e" and exponent */
738    if (realstyle == E_FORMAT)
739        padlen -= 2 + eplace;
740    zpadlen = max - fplace;
741    if (zpadlen < 0)
742        zpadlen = 0;
743    if (padlen < 0)
744        padlen = 0;
745    if (flags & DP_F_MINUS)
746        padlen = -padlen;
747
748    if ((flags & DP_F_ZERO) && (padlen > 0)) {
749        if (signvalue) {
750            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
751                return 0;
752            --padlen;
753            signvalue = 0;
754        }
755        while (padlen > 0) {
756            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
757                return 0;
758            --padlen;
759        }
760    }
761    while (padlen > 0) {
762        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
763            return 0;
764        --padlen;
765    }
766    if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
767        return 0;
768
769    while (iplace > 0) {
770        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
771            return 0;
772    }
773
774    /*
775     * Decimal point. This should probably use locale to find the correct
776     * char to print out.
777     */
778    if (max > 0 || (flags & DP_F_NUM)) {
779        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
780            return 0;
781
782        while (fplace > 0) {
783            if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
784                             fconvert[--fplace]))
785                return 0;
786        }
787    }
788    while (zpadlen > 0) {
789        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
790            return 0;
791        --zpadlen;
792    }
793    if (realstyle == E_FORMAT) {
794        char ech;
795
796        if ((flags & DP_F_UP) == 0)
797            ech = 'e';
798        else
799            ech = 'E';
800        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech))
801                return 0;
802        if (exp < 0) {
803            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-'))
804                    return 0;
805        } else {
806            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+'))
807                    return 0;
808        }
809        while (eplace > 0) {
810            if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
811                             econvert[--eplace]))
812                return 0;
813        }
814    }
815
816    while (padlen < 0) {
817        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
818            return 0;
819        ++padlen;
820    }
821    return 1;
822}
823
824#endif /* OPENSSL_SYS_UEFI */
825
826#define BUFFER_INC  1024
827
828static int
829doapr_outch(char **sbuffer,
830            char **buffer, size_t *currlen, size_t *maxlen, int c)
831{
832    /* If we haven't at least one buffer, someone has done a big booboo */
833    if (!ossl_assert(*sbuffer != NULL || buffer != NULL))
834        return 0;
835
836    /* |currlen| must always be <= |*maxlen| */
837    if (!ossl_assert(*currlen <= *maxlen))
838        return 0;
839
840    if (buffer && *currlen == *maxlen) {
841        if (*maxlen > INT_MAX - BUFFER_INC)
842            return 0;
843
844        *maxlen += BUFFER_INC;
845        if (*buffer == NULL) {
846            if ((*buffer = OPENSSL_malloc(*maxlen)) == NULL) {
847                BIOerr(BIO_F_DOAPR_OUTCH, ERR_R_MALLOC_FAILURE);
848                return 0;
849            }
850            if (*currlen > 0) {
851                if (!ossl_assert(*sbuffer != NULL))
852                    return 0;
853                memcpy(*buffer, *sbuffer, *currlen);
854            }
855            *sbuffer = NULL;
856        } else {
857            char *tmpbuf;
858            tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
859            if (tmpbuf == NULL)
860                return 0;
861            *buffer = tmpbuf;
862        }
863    }
864
865    if (*currlen < *maxlen) {
866        if (*sbuffer)
867            (*sbuffer)[(*currlen)++] = (char)c;
868        else
869            (*buffer)[(*currlen)++] = (char)c;
870    }
871
872    return 1;
873}
874
875/***************************************************************************/
876
877int BIO_printf(BIO *bio, const char *format, ...)
878{
879    va_list args;
880    int ret;
881
882    va_start(args, format);
883
884    ret = BIO_vprintf(bio, format, args);
885
886    va_end(args);
887    return ret;
888}
889
890int BIO_vprintf(BIO *bio, const char *format, va_list args)
891{
892    int ret;
893    size_t retlen;
894    char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
895                                 * in small-stack environments, like threads
896                                 * or DOS programs. */
897    char *hugebufp = hugebuf;
898    size_t hugebufsize = sizeof(hugebuf);
899    char *dynbuf = NULL;
900    int ignored;
901
902    dynbuf = NULL;
903    if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
904                args)) {
905        OPENSSL_free(dynbuf);
906        return -1;
907    }
908    if (dynbuf) {
909        ret = BIO_write(bio, dynbuf, (int)retlen);
910        OPENSSL_free(dynbuf);
911    } else {
912        ret = BIO_write(bio, hugebuf, (int)retlen);
913    }
914    return ret;
915}
916
917/*
918 * As snprintf is not available everywhere, we provide our own
919 * implementation. This function has nothing to do with BIOs, but it's
920 * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
921 * function should be renamed, but to what?)
922 */
923int BIO_snprintf(char *buf, size_t n, const char *format, ...)
924{
925    va_list args;
926    int ret;
927
928    va_start(args, format);
929
930    ret = BIO_vsnprintf(buf, n, format, args);
931
932    va_end(args);
933    return ret;
934}
935
936int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
937{
938    size_t retlen;
939    int truncated;
940
941    if (!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
942        return -1;
943
944    if (truncated)
945        /*
946         * In case of truncation, return -1 like traditional snprintf.
947         * (Current drafts for ISO/IEC 9899 say snprintf should return the
948         * number of characters that would have been written, had the buffer
949         * been large enough.)
950         */
951        return -1;
952    else
953        return (retlen <= INT_MAX) ? (int)retlen : -1;
954}
955