1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16
17/* [Standardize-exceptions] Use unsafe function: Portability
18 * [reason] Use unsafe function to implement security function to maintain platform compatibility.
19 *          And sufficient input validation is performed before calling
20 */
21
22#include "vsprintf_p.h"
23
24#ifndef OUTPUT_P_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5
25#define OUTPUT_P_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5
26
27#define SECUREC_FLOAT_BUFSIZE (309+40)  /* max float point value */
28#define SECUREC_FLOAT_BUFSIZE_LB (4932+40)  /* max long double value */
29
30#define SECUREC_INT_MAX       2147483647
31
32#define SECUREC_MUL10(x) ((((x) << 2) + (x)) << 1)
33#define SECUREC_INT_MAX_DIV_TEN       21474836
34#define SECUREC_MUL10_ADD_BEYOND_MAX(val) (((val) > SECUREC_INT_MAX_DIV_TEN))
35
36#ifdef SECUREC_STACK_SIZE_LESS_THAN_1K
37#define SECUREC_FMT_STR_LEN (8)
38#else
39#define SECUREC_FMT_STR_LEN (16)
40#endif
41
42typedef struct {
43    unsigned int flags;
44    int fldWidth;
45    int precision;
46    int bufferIsWide;           /* flag for buffer contains wide chars */
47    int dynWidth;               /* %*   1 width from variable parameter ;0 not */
48    int dynPrecision;           /* %.*  1 precision from variable parameter ;0 not */
49} SecFormatAttr;
50
51typedef union {
52    char *str;                  /* not a null terminated  string */
53    wchar_t *wStr;
54} SecFormatBuf;
55
56typedef union {
57    char str[SECUREC_BUFFER_SIZE + 1];
58#ifdef SECUREC_FOR_WCHAR
59    wchar_t wStr[SECUREC_BUFFER_SIZE + 1];
60#endif
61} SecBuffer;
62
63static int SecIndirectSprintf(char *strDest, size_t destMax, const char *format, ...)
64{
65    int ret;                    /* If initialization causes  e838 */
66    va_list arglist;
67
68    va_start(arglist, format);
69    SECUREC_MASK_MSVC_CRT_WARNING
70    ret = VsprintfP(strDest, destMax, format, arglist);
71    SECUREC_END_MASK_MSVC_CRT_WARNING
72    va_end(arglist);
73    (void)arglist;              /* to clear e438 last value assigned not used , the compiler will optimize this code */
74
75    return ret;
76}
77
78#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
79/* to clear e506 warning */
80static int SecIsSameSize(size_t sizeA, size_t sizeB)
81{
82    return sizeA == sizeB;
83}
84#endif
85
86#define SECUREC_SPECIAL(_val, Base) \
87            case Base: \
88            do { \
89                *--formatBuf.str = digits[_val % Base]; \
90            }while ((_val /= Base) != 0)
91
92#define SECUREC_SAFE_WRITE_PREFIX(src, txtLen, _stream, outChars) do { \
93            for (ii = 0; ii < txtLen; ++ii) { \
94                *((SecChar *)(void *)(_stream->cur)) = *(src); \
95                _stream->cur += sizeof(SecChar);              \
96                ++(src);                                      \
97            } \
98            _stream->count -= txtLen * (int)(sizeof(SecChar)); \
99            *(outChars) = *(outChars) + (txtLen); \
100        } SECUREC_WHILE_ZERO
101
102#define SECUREC_SAFE_WRITE_STR(src, txtLen, _stream, outChars) do { \
103            if (txtLen < 12 /* for mobile number length */) { \
104                for (ii = 0; ii < txtLen; ++ii) { \
105                    *((SecChar *)(void *)(_stream->cur)) = *(src); \
106                    _stream->cur += sizeof(SecChar); \
107                    ++(src); \
108                } \
109            } else { \
110                (void)memcpy(_stream->cur, src, ((size_t)(unsigned int)txtLen * (sizeof(SecChar)))); \
111                _stream->cur += (size_t)(unsigned int)txtLen * (sizeof(SecChar)); \
112            } \
113            _stream->count -= txtLen * (int)(sizeof(SecChar)); \
114            *(outChars) = *(outChars) + (txtLen); \
115        } SECUREC_WHILE_ZERO
116
117#define SECUREC_SAFE_WRITE_CHAR(_ch, _stream, outChars) do { \
118            *((SecChar *)(void *)(_stream->cur)) = (SecChar)_ch; \
119            _stream->cur += sizeof(SecChar); \
120            _stream->count -= (int)(sizeof(SecChar)); \
121            *(outChars) = *(outChars) + 1; \
122        } SECUREC_WHILE_ZERO
123
124#define SECUREC_SAFE_PADDING(padChar, padLen, _stream, outChars) do { \
125            for (ii = 0; ii < padLen; ++ii) { \
126                *((SecChar *)(void *)(_stream->cur)) = (SecChar)padChar; \
127                _stream->cur += sizeof(SecChar); \
128            } \
129            _stream->count -= padLen * (int)(sizeof(SecChar)); \
130            *(outChars) = *(outChars) + (padLen); \
131        } SECUREC_WHILE_ZERO
132
133/* The count variable can be reduced to 0, and the external function complements the \0 terminator. */
134#define SECUREC_IS_REST_BUF_ENOUGH(needLen) ((int)(stream->count - (int)needLen * (int)(sizeof(SecChar)))  >= 0)
135
136#define SECUREC_FMT_STATE_OFFSET  256
137#ifdef SECUREC_FOR_WCHAR
138#define SECUREC_FMT_TYPE(c, fmtTable)  ((((unsigned int)(int)(c)) <= (unsigned int)(int)SECUREC_CHAR('~')) ? \
139                                      (fmtTable[(unsigned char)(c)]) : 0)
140#define SECUREC_DECODE_STATE(c, fmtTable, laststate) (SecFmtState)(((fmtTable[(SECUREC_FMT_TYPE(c,fmtTable)) * \
141                                                                            ((unsigned char)STAT_INVALID + 1) + \
142                                                                            (unsigned char)(laststate) + \
143                                                                            SECUREC_FMT_STATE_OFFSET])))
144#else
145#define SECUREC_DECODE_STATE(c,fmtTable,laststate) (SecFmtState)((fmtTable[(fmtTable[(unsigned char)(c)]) * \
146                                                                           ((unsigned char)STAT_INVALID + 1) + \
147                                                                           (unsigned char)(laststate) + \
148                                                                           SECUREC_FMT_STATE_OFFSET]))
149#endif
150
151#define PUBLIC_FLAG_LEN  8
152#define PRIVATE_FLAG_LEN 9
153#define PUBLIC_FLAG      "{public}"
154#define PRIVATE_FLAG     "{private}"
155
156static void SecWritePrivateStr(SecPrintfStream *stream, int *pCharsOut)
157{
158    int ii = 0;
159#define PRIVATE_STR_LEN (9)
160#ifndef SECUREC_FOR_WCHAR
161    static const char PRIVACY_STRING[] = "<private>";
162    const char *pPrivStr = PRIVACY_STRING;
163
164    if (SECUREC_IS_REST_BUF_ENOUGH(PRIVATE_STR_LEN)) {
165        SECUREC_SAFE_WRITE_STR(pPrivStr, PRIVATE_STR_LEN, stream, pCharsOut);
166    } else {
167        SECUREC_WRITE_STRING(pPrivStr, PRIVATE_STR_LEN, stream, pCharsOut);
168    }
169#else
170    static const wchar_t wprivacyString[] = { L'<', L'p', L'r', L'i', L'v', L'a', L't', L'e', L'>', L'\0' };
171    const wchar_t *pwPrivStr = wprivacyString;
172
173    if (SECUREC_IS_REST_BUF_ENOUGH(PRIVATE_STR_LEN)) {
174        SECUREC_SAFE_WRITE_STR(pwPrivStr, PRIVATE_STR_LEN, stream, pCharsOut);
175    } else {
176        SECUREC_WRITE_STRING(pwPrivStr, PRIVATE_STR_LEN, stream, pCharsOut);
177    }
178#endif
179}
180
181static void SecDecodeFlags(SecChar ch, SecFormatAttr *attr)
182{
183    switch (ch) {
184    case SECUREC_CHAR(' '):
185        attr->flags |= SECUREC_FLAG_SIGN_SPACE;
186        break;
187    case SECUREC_CHAR('+'):
188        attr->flags |= SECUREC_FLAG_SIGN;
189        break;
190    case SECUREC_CHAR('-'):
191        attr->flags |= SECUREC_FLAG_LEFT;
192        break;
193    case SECUREC_CHAR('0'):
194        attr->flags |= SECUREC_FLAG_LEADZERO;   /* add zero th the front */
195        break;
196    case SECUREC_CHAR('#'):
197        attr->flags |= SECUREC_FLAG_ALTERNATE;  /* output %x with 0x */
198        break;
199    default:
200        break;
201    }
202    return;
203}
204
205static int SecDecodeSize(SecChar ch, SecFormatAttr *attr, const SecChar **format)
206{
207    switch (ch) {
208#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
209    case SECUREC_CHAR('j'):
210        attr->flags |= SECUREC_FLAG_INTMAX;
211        break;
212#endif
213    case SECUREC_CHAR('q'):  /* fall-through */ /* FALLTHRU */
214    case SECUREC_CHAR('L'):
215        attr->flags |= SECUREC_FLAG_LONGLONG | SECUREC_FLAG_LONG_DOUBLE;
216        break;
217    case SECUREC_CHAR('l'):
218        if (**format == SECUREC_CHAR('l')) {
219            ++(*format);
220            attr->flags |= SECUREC_FLAG_LONGLONG;   /* long long */
221        } else {
222            attr->flags |= SECUREC_FLAG_LONG;   /* long int or wchar_t */
223        }
224        break;
225    case SECUREC_CHAR('t'):
226        attr->flags |= SECUREC_FLAG_PTRDIFF;
227        break;
228#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
229    case SECUREC_CHAR('z'):
230        attr->flags |= SECUREC_FLAG_SIZE;
231        break;
232    case SECUREC_CHAR('Z'):
233        attr->flags |= SECUREC_FLAG_SIZE;
234        break;
235#endif
236
237    case SECUREC_CHAR('I'):
238#ifdef SECUREC_ON_64BITS
239        attr->flags |= SECUREC_FLAG_I64;    /* %I  to  INT64 */
240#endif
241        if ((**format == SECUREC_CHAR('6')) && (*((*format) + 1) == SECUREC_CHAR('4'))) {
242            (*format) += 2;
243            attr->flags |= SECUREC_FLAG_I64;    /* %I64  to  INT64 */
244        } else if ((**format == SECUREC_CHAR('3')) && (*((*format) + 1) == SECUREC_CHAR('2'))) {
245            (*format) += 2;
246            attr->flags &= ~SECUREC_FLAG_I64;   /* %I64  to  INT32 */
247        } else if ((**format == SECUREC_CHAR('d')) || (**format == SECUREC_CHAR('i')) ||
248                   (**format == SECUREC_CHAR('o')) || (**format == SECUREC_CHAR('u')) ||
249                   (**format == SECUREC_CHAR('x')) || (**format == SECUREC_CHAR('X'))) {
250            /* do nothing */
251        } else {
252            /* Compatibility  code for "%I" just print I */
253            return -1;
254        }
255        break;
256
257    case SECUREC_CHAR('h'):
258        if (**format == SECUREC_CHAR('h')) {
259            attr->flags |= SECUREC_FLAG_CHAR;   /* char */
260        } else {
261            attr->flags |= SECUREC_FLAG_SHORT;  /* short int */
262        }
263        break;
264
265    case SECUREC_CHAR('w'):
266        attr->flags |= SECUREC_FLAG_WIDECHAR;   /* wide char */
267        break;
268    default:
269        break;
270
271    }
272
273    return 0;
274}
275
276static int SecDecodeTypeC(SecFormatAttr *attr, unsigned int cValue, SecFormatBuf *formatBuf, SecBuffer *buffer)
277{
278    int textLen;
279    wchar_t wchar;
280
281#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && !(defined(__hpux)) && !(defined(SECUREC_ON_SOLARIS))
282    attr->flags &= ~SECUREC_FLAG_LEADZERO;
283#endif
284
285#ifdef SECUREC_FOR_WCHAR
286    attr->bufferIsWide = 1;
287    wchar = (wchar_t)cValue;
288    if (attr->flags & SECUREC_FLAG_SHORT) {
289        /* multibyte character to wide  character */
290        char tempchar[2];
291        tempchar[0] = (char)(wchar & 0x00ff);
292        tempchar[1] = '\0';
293
294        if (mbtowc(buffer->wStr, tempchar, sizeof(tempchar)) < 0) {
295            return -1;
296        }
297    } else {
298        buffer->wStr[0] = wchar;
299    }
300    formatBuf->wStr = buffer->wStr;
301    textLen = 1;                /* only 1 wide character */
302#else
303    attr->bufferIsWide = 0;
304    if (attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) {
305        wchar = (wchar_t)cValue;
306        /* wide  character  to multibyte character */
307        SECUREC_MASK_MSVC_CRT_WARNING
308        textLen = wctomb(buffer->str, wchar);
309        SECUREC_END_MASK_MSVC_CRT_WARNING
310        if (textLen < 0) {
311            return -1;
312        }
313    } else {
314        /* get  multibyte character from argument */
315        unsigned short temp;
316        temp = (unsigned short)cValue;
317        buffer->str[0] = (char)temp;
318        textLen = 1;
319    }
320    formatBuf->str = buffer->str;
321#endif
322
323    return textLen;
324}
325
326static int SecDecodeTypeS(SecFormatAttr *attr, char *argPtr, SecFormatBuf *formatBuf)
327{
328    /* literal string to print null ptr, define it on stack rather than const text area
329       is to avoid gcc warning with pointing const text with variable */
330    static char strNullString[8] = "(null)";
331    static wchar_t wStrNullString[8] = { L'(', L'n', L'u', L'l', L'l', L')', L'\0', L'\0' };
332
333    int finalPrecision;
334    char *strEnd = NULL;
335    wchar_t *wStrEnd = NULL;
336    int textLen;
337
338#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && (!defined(SECUREC_ON_UNIX))
339    attr->flags &= ~SECUREC_FLAG_LEADZERO;
340#endif
341    finalPrecision = (attr->precision == -1) ? SECUREC_INT_MAX : attr->precision;
342    formatBuf->str = argPtr;
343
344#ifdef SECUREC_FOR_WCHAR
345#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT)
346    if (!(attr->flags & SECUREC_FLAG_LONG)) {
347        attr->flags |= SECUREC_FLAG_SHORT;
348    }
349#endif
350    if (attr->flags & SECUREC_FLAG_SHORT) {
351        if (formatBuf->str == NULL) {   /* NULL passed, use special string */
352            formatBuf->str = strNullString;
353        }
354        strEnd = formatBuf->str;
355        for (textLen = 0; textLen < finalPrecision && *strEnd; textLen++) {
356            ++strEnd;
357        }
358        /* textLen now contains length in multibyte chars */
359    } else {
360        if (formatBuf->wStr == NULL) {  /* NULL passed, use special string */
361            formatBuf->wStr = wStrNullString;
362        }
363        attr->bufferIsWide = 1;
364        wStrEnd = formatBuf->wStr;
365        while (finalPrecision-- && *wStrEnd) {
366            ++wStrEnd;
367        }
368        textLen = (int)(wStrEnd - formatBuf->wStr); /* in wchar_ts */
369        /* textLen now contains length in wide chars */
370    }
371#else /* SECUREC_FOR_WCHAR */
372    if (attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) {
373        if (formatBuf->wStr == NULL) {  /* NULL passed, use special string */
374            formatBuf->wStr = wStrNullString;
375        }
376        attr->bufferIsWide = 1;
377        wStrEnd = formatBuf->wStr;
378        while (finalPrecision-- && *wStrEnd) {
379            ++wStrEnd;
380        }
381        textLen = (int)(wStrEnd - formatBuf->wStr);
382    } else {
383        if (formatBuf->str == NULL) {   /* meet NULL, use special string */
384            formatBuf->str = strNullString;
385        }
386
387        if (finalPrecision == SECUREC_INT_MAX) {
388            /* precision NOT assigned */
389            /* The strlen performance is high when the string length is greater than 32 */
390            textLen = (int)strlen(formatBuf->str);
391        } else {
392            /* precision assigned */
393            strEnd = formatBuf->str;
394            while (finalPrecision-- && *strEnd) {
395                ++strEnd;
396            }
397            textLen = (int)(strEnd - formatBuf->str);   /* length of the string */
398        }
399
400    }
401
402#endif /* SECUREC_FOR_WCHAR */
403    return textLen;
404}
405
406HILOG_LOCAL_API
407int SecOutputPS(SecPrintfStream *stream, int priv, const char *cformat, va_list arglist)
408{
409    const SecChar *format = cformat;
410
411    char *floatBuf = NULL;
412    SecFormatBuf formatBuf;
413    static const char *itoaUpperDigits = "0123456789ABCDEFX";
414    static const char *itoaLowerDigits = "0123456789abcdefx";
415    const char *digits = itoaUpperDigits;
416    int ii = 0;
417
418    unsigned int radix;
419    int charsOut;               /* characters written */
420
421    int prefixLen = 0;
422    int padding = 0;
423
424    int textLen;                /* length of the text */
425    int bufferSize = 0;         /* size of formatBuf.str */
426    int noOutput = 0;
427
428    SecFmtState state;
429    SecFmtState laststate;
430
431    SecChar prefix[2] = { 0 };
432    SecChar ch;                 /* currently read character */
433
434    static const unsigned char FMT_CHAR_TABLE[337] = {
435        /* type 0:    nospecial meaning;
436           1:   '%';
437           2:    '.'
438           3:    '*'
439           4:    '0'
440           5:    '1' ... '9'
441           6:    ' ', '+', '-', '#'
442           7:     'h', 'l', 'L', 'F', 'w' , 'N','z','q','t','j'
443           8:     'd','o','u','i','x','X','e','f','g'
444         */
445        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
446        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
447        0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x00,
448        0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
449        0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00,
450        0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
451        0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x07, 0x00, 0x07, 0x00, 0x00, 0x08,
452        0x08, 0x07, 0x00, 0x08, 0x07, 0x08, 0x00, 0x07, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
453        /* fill zero  for normal char 128 byte for 0x80 - 0xff */
454        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
455        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
456        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
457        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
458        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
462        /* state  0: normal
463           1: percent
464           2: flag
465           3: width
466           4: dot
467           5: precis
468           6: size
469           7: type
470           8: invalid
471         */
472        0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,
473        0x01, 0x00, 0x00, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, 0x08, 0x05,
474        0x08, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03,
475        0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
476        0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00,
477        0x00
478    };
479
480    SecFormatAttr formatAttr;
481    SecBuffer buffer;
482    formatAttr.flags = 0;
483    formatAttr.bufferIsWide = 0;    /* flag for buffer contains wide chars */
484    formatAttr.fldWidth = 0;
485    formatAttr.precision = 0;
486    formatAttr.dynWidth = 0;
487    formatAttr.dynPrecision = 0;
488
489    charsOut = 0;
490    textLen = 0;
491    state = STAT_NORMAL;        /* starting state */
492    formatBuf.str = NULL;
493
494    int isPrivacy = 1; /*whether show private string*/
495
496    /* loop each format character */
497    /* remove format != NULL */
498    while ((ch = *format++) != SECUREC_CHAR('\0') && charsOut >= 0) {
499        laststate = state;
500        state = SECUREC_DECODE_STATE(ch, FMT_CHAR_TABLE, laststate);
501
502        switch (state) {
503        case STAT_NORMAL:
504
505NORMAL_CHAR:
506
507            /* normal state, write character */
508            if (SECUREC_IS_REST_BUF_ENOUGH(1 /* only one char */ )) {
509                SECUREC_SAFE_WRITE_CHAR(ch, stream, &charsOut); /* char * cast to wchar * */
510            } else {
511#ifdef SECUREC_FOR_WCHAR
512                SECUREC_WRITE_CHAR(ch, stream, &charsOut);
513#else
514                /* optimize function call to code */
515                charsOut = -1;
516                stream->count = -1;
517#endif
518            }
519
520            continue;
521
522        case STAT_PERCENT:
523            /* set default values */
524            prefixLen = 0;
525            noOutput = 0;
526            formatAttr.flags = 0;
527            formatAttr.fldWidth = 0;
528            formatAttr.precision = -1;
529            formatAttr.bufferIsWide = 0;
530            if (*format == SECUREC_CHAR('{')) {
531                if (strncmp(format, PUBLIC_FLAG, PUBLIC_FLAG_LEN) == 0) {
532                    isPrivacy = 0;
533                    format += PUBLIC_FLAG_LEN;
534                }
535                else if (strncmp(format, PRIVATE_FLAG, PRIVATE_FLAG_LEN) == 0) {
536                    isPrivacy = 1;
537                    format += PRIVATE_FLAG_LEN;
538                }
539            }
540            else {
541                isPrivacy = 1;
542            }
543
544            if (priv == 0) {
545                isPrivacy = 0;
546            }
547
548            break;
549
550        case STAT_FLAG:
551            /* set flag based on which flag character */
552            SecDecodeFlags(ch, &formatAttr);
553            break;
554
555        case STAT_WIDTH:
556            /* update width value */
557            if (ch == SECUREC_CHAR('*')) {
558                /* get width */
559                formatAttr.fldWidth = (int)va_arg(arglist, int);
560                if (formatAttr.fldWidth < 0) {
561                    formatAttr.flags |= SECUREC_FLAG_LEFT;
562                    formatAttr.fldWidth = -formatAttr.fldWidth;
563                }
564                formatAttr.dynWidth = 1;
565            } else {
566                if (laststate != STAT_WIDTH) {
567                    formatAttr.fldWidth = 0;
568                }
569                if (SECUREC_MUL10_ADD_BEYOND_MAX(formatAttr.fldWidth)) {
570                    return -1;
571                }
572                formatAttr.fldWidth = (int)SECUREC_MUL10((unsigned int)formatAttr.fldWidth) + (ch - SECUREC_CHAR('0'));
573                formatAttr.dynWidth = 0;
574            }
575            break;
576
577        case STAT_DOT:
578            formatAttr.precision = 0;
579            break;
580
581        case STAT_PRECIS:
582            /* update precision value */
583            if (ch == SECUREC_CHAR('*')) {
584                /* get precision from arg list */
585                formatAttr.precision = (int)va_arg(arglist, int);
586                if (formatAttr.precision < 0) {
587                    formatAttr.precision = -1;
588                }
589                formatAttr.dynPrecision = 1;
590            } else {
591                /* add digit to current precision */
592                if (SECUREC_MUL10_ADD_BEYOND_MAX(formatAttr.precision)) {
593                    return -1;
594                }
595                formatAttr.precision =
596                    (int)SECUREC_MUL10((unsigned int)formatAttr.precision) + (ch - SECUREC_CHAR('0'));
597                formatAttr.dynPrecision = 0;
598            }
599            break;
600
601        case STAT_SIZE:
602            /* read a size specifier, set the formatAttr.flags based on it */
603            if (SecDecodeSize(ch, &formatAttr, &format) != 0) {
604                /* Compatibility  code for "%I" just print I */
605                state = STAT_NORMAL;
606                goto NORMAL_CHAR;
607            }
608            break;
609
610        case STAT_TYPE:
611
612            switch (ch) {
613
614            case SECUREC_CHAR('C'):
615                /* wide char */
616                if (!(formatAttr.flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR))) {
617
618#ifdef SECUREC_FOR_WCHAR
619                    formatAttr.flags |= SECUREC_FLAG_SHORT;
620#else
621                    formatAttr.flags |= SECUREC_FLAG_WIDECHAR;
622#endif
623                }
624                /* fall-through */
625                /* FALLTHRU */
626            case SECUREC_CHAR('c'):
627                {
628                    unsigned int cValue = (unsigned int)va_arg(arglist, int);
629                    /*if it's a private arg, just write <priate> to stream*/
630                    if (isPrivacy == 1) {
631                        break;
632                    }
633                    textLen = SecDecodeTypeC(&formatAttr, cValue, &formatBuf, &buffer);
634                    if (textLen < 0) {
635                        noOutput = 1;
636                    }
637                }
638                break;
639            case SECUREC_CHAR('S'):    /* wide char string */
640#ifndef SECUREC_FOR_WCHAR
641                if (!(formatAttr.flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR))) {
642                    formatAttr.flags |= SECUREC_FLAG_WIDECHAR;
643                }
644#else
645                if (!(formatAttr.flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR))) {
646                    formatAttr.flags |= SECUREC_FLAG_SHORT;
647                }
648#endif
649                /* fall-through */
650                /* FALLTHRU */
651            case SECUREC_CHAR('s'):
652                {
653                    char *argPtr = (char *)va_arg(arglist, char *);
654                    /*if it's a private arg, just write <priate> to stream*/
655                    if (isPrivacy == 1) {
656                        break;
657                    }
658                    textLen = SecDecodeTypeS(&formatAttr, argPtr, &formatBuf);
659                }
660                break;
661
662            case SECUREC_CHAR('n'):
663                /* higher risk disable it */
664                return -1;
665
666            case SECUREC_CHAR('E'):    /* fall-through */ /* FALLTHRU */
667            case SECUREC_CHAR('F'):    /* fall-through */ /* FALLTHRU */
668            case SECUREC_CHAR('G'):    /* fall-through */ /* FALLTHRU */
669            case SECUREC_CHAR('A'):    /* fall-through */ /* FALLTHRU */
670                /* convert format char to lower , use Explicit conversion to clean up compilation warning */
671                ch = (SecChar)(ch + ((SecChar)(SECUREC_CHAR('a')) - (SECUREC_CHAR('A'))));
672                /* fall-through */
673                /* FALLTHRU */
674            case SECUREC_CHAR('e'):    /* fall-through */ /* FALLTHRU */
675            case SECUREC_CHAR('f'):    /* fall-through */ /* FALLTHRU */
676            case SECUREC_CHAR('g'):    /* fall-through */ /* FALLTHRU */
677            case SECUREC_CHAR('a'):
678                {
679                    /*if it's a private arg, just write <priate> to stream*/
680                    if (isPrivacy == 1) {
681#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
682                        if (formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) {
683                            (void)va_arg(arglist, long double);
684                        } else
685#endif
686                        {
687                            (void)va_arg(arglist, double);
688                        }
689                        break;
690                    }
691
692                    /* floating point conversion */
693                    formatBuf.str = buffer.str; /* output buffer for float string with default size */
694                    size_t formatBufLen = sizeof(buffer);
695
696                    /* compute the precision value */
697                    if (formatAttr.precision < 0) {
698                        formatAttr.precision = 6;
699                    } else if (formatAttr.precision == 0 && ch == SECUREC_CHAR('g')) {
700                        formatAttr.precision = 1;
701                    }
702
703                    /* calc buffer size to store long double value */
704                    if (formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) {
705                        if (formatAttr.precision > (SECUREC_INT_MAX - SECUREC_FLOAT_BUFSIZE_LB)) {
706                            noOutput = 1;
707                            break;
708                        }
709                        bufferSize = SECUREC_FLOAT_BUFSIZE_LB + formatAttr.precision;
710                    } else {
711                        if (formatAttr.precision > (SECUREC_INT_MAX - SECUREC_FLOAT_BUFSIZE)) {
712                            noOutput = 1;
713                            break;
714                        }
715                        bufferSize = SECUREC_FLOAT_BUFSIZE + formatAttr.precision;
716                    }
717                    if (formatAttr.fldWidth > bufferSize) {
718                        bufferSize = formatAttr.fldWidth;
719                    }
720
721                    if (bufferSize >= SECUREC_BUFFER_SIZE) {
722                        /* the current value of SECUREC_BUFFER_SIZE could NOT store the formatted float string */
723                        formatBufLen = (size_t)(unsigned int)bufferSize + (size_t)2; // size 2: include '+' and '\0'
724                        floatBuf = (char *)SECUREC_MALLOC(formatBufLen);
725                        if (floatBuf != NULL) {
726                            formatBuf.str = floatBuf;
727                        } else {
728                            noOutput = 1;
729                            break;
730                        }
731                    }
732
733                    {
734                        /* add following code to call system sprintf API for float number */
735                        const SecChar *pFltFmt = format - 2;    /* point to the position before 'f' or 'g' */
736                        int k;
737                        int fltFmtStrLen;
738                        char fltFmtBuf[SECUREC_FMT_STR_LEN];
739                        char *fltFmtStr = fltFmtBuf;
740                        char *fltFmtHeap = NULL;    /* to clear warning */
741
742                        /* must meet '%' (normal format) or '}'(with{private} or{public} format)*/
743                        while (*pFltFmt != SECUREC_CHAR('%') && *pFltFmt != SECUREC_CHAR('}')) {
744                            --pFltFmt;
745                        }
746                        fltFmtStrLen = (int)((format - pFltFmt) + 1);   /* with ending terminator */
747                        if (fltFmtStrLen > SECUREC_FMT_STR_LEN) {
748                            /* if SECUREC_FMT_STR_LEN is NOT enough, alloc a new buffer */
749                            fltFmtHeap = (char *)SECUREC_MALLOC((size_t)((unsigned int)fltFmtStrLen));
750                            if (fltFmtHeap == NULL) {
751                                noOutput = 1;
752                                break;
753                            } else {
754                                fltFmtHeap[0] = '%';
755                                for (k = 1; k < fltFmtStrLen - 1; ++k) {
756                                    /* convert wchar to char */
757                                    fltFmtHeap[k] = (char)(pFltFmt[k]); /* copy the format string */
758                                }
759                                fltFmtHeap[k] = '\0';
760
761                                fltFmtStr = fltFmtHeap;
762                            }
763                        } else {
764                            /* purpose of the repeat code is to solve the tool alarm  Redundant_Null_Check */
765                            fltFmtBuf[0] = '%';
766                            for (k = 1; k < fltFmtStrLen - 1; ++k) {
767                                /* convert wchar to char */
768                                fltFmtBuf[k] = (char)(pFltFmt[k]);  /* copy the format string */
769                            }
770                            fltFmtBuf[k] = '\0';
771                        }
772
773#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
774                        if (formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) {
775                            long double tmp = (long double)va_arg(arglist, long double);
776                            /* call system sprintf to format float value */
777                            if (formatAttr.dynWidth && formatAttr.dynPrecision) {
778                                textLen = SecIndirectSprintf(formatBuf.str, formatBufLen, (char *)fltFmtStr,
779                                                             formatAttr.fldWidth,formatAttr.precision, tmp);
780                            } else if (formatAttr.dynWidth) {
781                                textLen = SecIndirectSprintf(formatBuf.str, formatBufLen, (char *)fltFmtStr,
782                                                             formatAttr.fldWidth, tmp);
783                            } else if (formatAttr.dynPrecision) {
784                                textLen = SecIndirectSprintf(formatBuf.str, formatBufLen, (char *)fltFmtStr,
785                                                             formatAttr.precision, tmp);
786                            } else {
787                                textLen = SecIndirectSprintf(formatBuf.str, formatBufLen, (char *)fltFmtStr, tmp);
788                            }
789                        } else
790#endif
791                        {
792                            double tmp = (double)va_arg(arglist, double);
793                            if (formatAttr.dynWidth && formatAttr.dynPrecision) {
794                                textLen = SecIndirectSprintf(formatBuf.str, formatBufLen, (char *)fltFmtStr,
795                                                             formatAttr.fldWidth, formatAttr.precision, tmp);
796                            } else if (formatAttr.dynWidth) {
797                                textLen = SecIndirectSprintf(formatBuf.str, formatBufLen, (char *)fltFmtStr,
798                                                             formatAttr.fldWidth, tmp);
799                            } else if (formatAttr.dynPrecision) {
800                                textLen = SecIndirectSprintf(formatBuf.str, formatBufLen, (char *)fltFmtStr,
801                                                             formatAttr.precision, tmp);
802                            } else {
803                                textLen = SecIndirectSprintf(formatBuf.str, formatBufLen, (char *)fltFmtStr, tmp);
804                            }
805                        }
806
807                        if (fltFmtHeap != NULL) {
808                            /* if buffer is allocated on heap, free it */
809                            SECUREC_FREE(fltFmtHeap);
810                            fltFmtHeap = NULL;
811                            /* to clear e438 last value assigned not used , the compiler will optimize this code */
812                            (void)fltFmtHeap;
813                        }
814                        if (textLen < 0) {
815                            /* bufferSize is large enough,just validation the return value */
816                            noOutput = 1;
817                            break;
818                        }
819
820                        formatAttr.fldWidth = textLen;  /* no padding ,this variable to calculate amount of padding */
821                        prefixLen = 0;  /* no padding ,this variable to  calculate amount of padding */
822                        formatAttr.flags = 0;   /* clear all internal formatAttr.flags */
823                        break;
824                    }
825                }
826
827            case SECUREC_CHAR('p'):
828                /* print a pointer */
829#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
830                formatAttr.flags &= ~SECUREC_FLAG_LEADZERO;
831#else
832                formatAttr.flags |= SECUREC_FLAG_POINTER;
833#endif
834
835#ifdef SECUREC_ON_64BITS
836                formatAttr.flags |= SECUREC_FLAG_I64;   /* converting an int64 */
837#else
838                formatAttr.flags |= SECUREC_FLAG_LONG;  /* converting a long */
839#endif
840
841#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) && (!defined(SECUREC_ON_UNIX))
842
843#if defined(SECUREC_VXWORKS_PLATFORM)
844                formatAttr.precision = 1;
845#else
846                formatAttr.precision = 0;
847#endif
848                formatAttr.flags |= SECUREC_FLAG_ALTERNATE; /* "0x" is not default prefix in UNIX */
849                digits = itoaLowerDigits;
850                goto OUTPUT_HEX;
851#else
852/* not linux vxwoks */
853#if defined(_AIX) || defined(SECUREC_ON_SOLARIS)
854                formatAttr.precision = 1;
855#else
856                formatAttr.precision = 2 * sizeof(void *);
857#endif
858
859#endif
860
861#if defined(SECUREC_ON_UNIX)
862                digits = itoaLowerDigits;
863                goto OUTPUT_HEX;
864#endif
865
866                /* fall-through */
867                /* FALLTHRU */
868            case SECUREC_CHAR('X'):
869                /* unsigned upper hex output */
870                digits = itoaUpperDigits;
871                goto OUTPUT_HEX;
872            case SECUREC_CHAR('x'):
873                /* unsigned lower hex output */
874                digits = itoaLowerDigits;
875
876OUTPUT_HEX:
877                radix = 16;
878                if (formatAttr.flags & SECUREC_FLAG_ALTERNATE) {
879                    /* alternate form means '0x' prefix */
880                    prefix[0] = SECUREC_CHAR('0');
881                    prefix[1] = (SecChar)(digits[16]); /* 'x' or 'X' */
882
883#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM))
884                    if (ch == 'p') {
885                        prefix[1] = SECUREC_CHAR('x');
886                    }
887#endif
888#if defined(_AIX) || defined(SECUREC_ON_SOLARIS)
889                    if (ch == 'p') {
890                        prefixLen = 0;
891                    } else {
892                        prefixLen = 2;
893                    }
894#else
895                    prefixLen = 2;
896#endif
897
898                }
899                goto OUTPUT_INT;
900            case SECUREC_CHAR('i'):    /* fall-through */ /* FALLTHRU */
901            case SECUREC_CHAR('d'):    /* fall-through */ /* FALLTHRU */
902                /* signed decimal output */
903                formatAttr.flags |= SECUREC_FLAG_SIGNED;
904                /* fall-through */
905                /* FALLTHRU */
906            case SECUREC_CHAR('u'):
907                radix = 10;
908                goto OUTPUT_INT;
909            case SECUREC_CHAR('o'):
910                /* unsigned octal output */
911                radix = 8;
912                if (formatAttr.flags & SECUREC_FLAG_ALTERNATE) {
913                    /* alternate form means force a leading 0 */
914                    formatAttr.flags |= SECUREC_FLAG_FORCE_OCTAL;
915                }
916OUTPUT_INT:
917                {
918
919                    SecUnsignedInt64 number = 0;    /* number to convert */
920                    SecInt64 l; /* temp long value */
921                    unsigned char tch;
922#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)
923                    SecUnsignedInt32 digit = 0; /* ascii value of digit */
924                    SecUnsignedInt32 quotientHigh = 0;
925                    SecUnsignedInt32 quotientLow = 0;
926#endif
927
928                    /* read argument into variable l */
929                    if (formatAttr.flags & SECUREC_FLAG_I64) {
930                        l = (SecInt64)va_arg(arglist, SecInt64);
931                    } else if (formatAttr.flags & SECUREC_FLAG_LONGLONG) {
932                        l = (SecInt64)va_arg(arglist, SecInt64);
933                    } else
934#ifdef SECUREC_ON_64BITS
935                    if (formatAttr.flags & SECUREC_FLAG_LONG) {
936                        l = (long)va_arg(arglist, long);
937                    } else
938#endif /* SECUREC_ON_64BITS */
939                    if (formatAttr.flags & SECUREC_FLAG_CHAR) {
940                        if (formatAttr.flags & SECUREC_FLAG_SIGNED) {
941                            l = (char)va_arg(arglist, int); /* sign extend */
942                            if (l >= 128) { /* on some platform, char is always unsigned */
943                                SecUnsignedInt64 tmpL = (SecUnsignedInt64)l;
944                                formatAttr.flags |= SECUREC_FLAG_NEGATIVE;
945                                tch = (unsigned char)(~(tmpL));
946                                l = tch + 1;
947                            }
948                        } else {
949                            l = (unsigned char)va_arg(arglist, int);    /* zero-extend */
950                        }
951
952                    } else if (formatAttr.flags & SECUREC_FLAG_SHORT) {
953                        if (formatAttr.flags & SECUREC_FLAG_SIGNED) {
954                            l = (short)va_arg(arglist, int);    /* sign extend */
955                        } else {
956                            l = (unsigned short)va_arg(arglist, int);   /* zero-extend */
957                        }
958
959                    }
960#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
961                    else if (formatAttr.flags & SECUREC_FLAG_PTRDIFF) {
962                        l = (ptrdiff_t)va_arg(arglist, ptrdiff_t);  /* sign extend */
963                    } else if (formatAttr.flags & SECUREC_FLAG_SIZE) {
964                        if (formatAttr.flags & SECUREC_FLAG_SIGNED) {
965                            /* No suitable macros were found to handle the branch */
966                            if (SecIsSameSize(sizeof(size_t), sizeof(long))) {
967                                l = va_arg(arglist, long);  /* sign extend */
968                            } else if (SecIsSameSize(sizeof(size_t), sizeof(long long))) {
969                                l = va_arg(arglist, long long); /* sign extend */
970                            } else {
971                                l = va_arg(arglist, int);   /* sign extend */
972                            }
973                        } else {
974                            l = (SecInt64)(size_t)va_arg(arglist, size_t);  /* sign extend */
975                        }
976                    } else if (formatAttr.flags & SECUREC_FLAG_INTMAX) {
977                        if (formatAttr.flags & SECUREC_FLAG_SIGNED) {
978                            l = va_arg(arglist, SecInt64);  /* sign extend */
979                        } else {
980                            l = (SecInt64)(SecUnsignedInt64)va_arg(arglist, SecUnsignedInt64);  /* sign extend */
981                        }
982                    }
983#endif
984                    else {
985                        if (formatAttr.flags & SECUREC_FLAG_SIGNED) {
986                            l = va_arg(arglist, int);   /* sign extend */
987                        } else {
988                            l = (unsigned int)va_arg(arglist, int); /* zero-extend */
989                        }
990
991                    }
992                    /*if it's a private arg, just write <priate> to stream*/
993                    if (isPrivacy == 1) {
994                        break;
995                    }
996
997                    /* check for negative; copy into number */
998                    if ((formatAttr.flags & SECUREC_FLAG_SIGNED) && l < 0) {
999                        number = (SecUnsignedInt64)(-l);
1000                        formatAttr.flags |= SECUREC_FLAG_NEGATIVE;
1001                    } else {
1002                        number = (SecUnsignedInt64)l;
1003                    }
1004
1005                    if (((formatAttr.flags & SECUREC_FLAG_I64) == 0) &&
1006#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
1007                        ((formatAttr.flags & SECUREC_FLAG_INTMAX) == 0) &&
1008#endif
1009#ifdef SECUREC_ON_64BITS
1010                        ((formatAttr.flags & SECUREC_FLAG_PTRDIFF) == 0) &&
1011                        ((formatAttr.flags & SECUREC_FLAG_SIZE) == 0) &&
1012#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT)  /* on window 64 system sizeof long is 32bit */
1013                        ((formatAttr.flags & SECUREC_FLAG_LONG) == 0) &&
1014#endif
1015#endif
1016                        ((formatAttr.flags & SECUREC_FLAG_LONGLONG) == 0)) {
1017
1018                            number &= 0xffffffff;
1019                    }
1020
1021                    /* check precision value for default */
1022                    if (formatAttr.precision < 0) {
1023                        formatAttr.precision = 1;   /* default precision */
1024                    } else {
1025#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
1026                        formatAttr.flags &= ~SECUREC_FLAG_LEADZERO;
1027#else
1028                        if (!(formatAttr.flags & SECUREC_FLAG_POINTER)) {
1029                            formatAttr.flags &= ~SECUREC_FLAG_LEADZERO;
1030                        }
1031#endif
1032                        if (formatAttr.precision > SECUREC_MAX_PRECISION) {
1033                            formatAttr.precision = SECUREC_MAX_PRECISION;
1034                        }
1035                    }
1036
1037                    /* Check if data is 0; if so, turn off hex prefix,if 'p',add 0x prefix,else not add prefix */
1038                    if (number == 0) {
1039#if !(defined(SECUREC_VXWORKS_PLATFORM)||defined(__hpux))
1040                        prefixLen = 0;
1041#else
1042                        if ((ch == 'p') && (formatAttr.flags & SECUREC_FLAG_ALTERNATE))
1043                            prefixLen = 2;
1044                        else
1045                            prefixLen = 0;
1046#endif
1047                    }
1048
1049                    /* Convert data to ASCII */
1050                    formatBuf.str = &buffer.str[SECUREC_BUFFER_SIZE];
1051
1052                    if (number > 0) {
1053#ifdef SECUREC_ON_64BITS
1054                        switch (radix) {
1055                            /* the compiler will optimize each one */
1056                            SECUREC_SPECIAL(number, 10);
1057                            break;
1058                            SECUREC_SPECIAL(number, 16);
1059                            break;
1060                            SECUREC_SPECIAL(number, 8);
1061                            break;
1062                        default:
1063                            break;
1064                        }
1065#else /* for 32 bits system */
1066                        if (number <= 0xFFFFFFFFUL) {
1067                            /* in most case, the value to be converted is small value */
1068                            SecUnsignedInt32 n32Tmp = (SecUnsignedInt32)number;
1069                            switch (radix) {
1070                                SECUREC_SPECIAL(n32Tmp, 16);
1071                                break;
1072                                SECUREC_SPECIAL(n32Tmp, 8);
1073                                break;
1074
1075#ifdef _AIX
1076                                /* the compiler will optimize div 10 */
1077                                SECUREC_SPECIAL(n32Tmp, 10);
1078                                break;
1079#else
1080                            case 10:
1081                                {
1082                                    /* fast div 10 */
1083                                    SecUnsignedInt32 q;
1084                                    SecUnsignedInt32 r;
1085                                    do {
1086                                        *--formatBuf.str = digits[n32Tmp % 10];
1087                                        q = (n32Tmp >> 1) + (n32Tmp >> 2);
1088                                        q = q + (q >> 4);
1089                                        q = q + (q >> 8);
1090                                        q = q + (q >> 16);
1091                                        q = q >> 3;
1092                                        r = n32Tmp - (((q << 2) + q) << 1);
1093                                        n32Tmp = (r > 9) ? (q + 1) : q;
1094                                    } while (n32Tmp != 0);
1095                                }
1096                                break;
1097#endif
1098                            default:
1099                                break;
1100                            }   /* end switch */
1101                        } else {
1102                            /* the value to be converted is greater than 4G */
1103#if defined(SECUREC_VXWORKS_VERSION_5_4)
1104                            do {
1105                                if (0 != SecU64Div32((SecUnsignedInt32)((number >> 16) >> 16),
1106                                                     (SecUnsignedInt32)number,
1107                                                     (SecUnsignedInt32)radix, &quotientHigh, &quotientLow, &digit)) {
1108                                    noOutput = 1;
1109                                    break;
1110                                }
1111                                *--formatBuf.str = digits[digit];
1112
1113                                number = (SecUnsignedInt64)quotientHigh;
1114                                number = (number << 32) + quotientLow;
1115                            } while (number != 0);
1116#else
1117                            switch (radix) {
1118                                /* the compiler will optimize div 10 */
1119                                SECUREC_SPECIAL(number, 10);
1120                                break;
1121                                SECUREC_SPECIAL(number, 16);
1122                                break;
1123                                SECUREC_SPECIAL(number, 8);
1124                                break;
1125                            default:
1126                                break;
1127                            }
1128#endif
1129                        }
1130#endif
1131                    }           /* END if (number > 0) */
1132                    /* compute length of number,.if textLen > 0, then formatBuf.str must be in buffer.str */
1133                    textLen = (int)((char *)&buffer.str[SECUREC_BUFFER_SIZE] - formatBuf.str);
1134                    if (formatAttr.precision > textLen) {
1135                        for (ii = 0; ii < formatAttr.precision - textLen; ++ii) {
1136                            *--formatBuf.str = '0';
1137                        }
1138                        textLen = formatAttr.precision;
1139                    }
1140
1141                    /* Force a leading zero if FORCEOCTAL flag set */
1142                    if ((formatAttr.flags & SECUREC_FLAG_FORCE_OCTAL) && (textLen == 0 || formatBuf.str[0] != '0')) {
1143                        *--formatBuf.str = '0';
1144                        ++textLen;  /* add a zero */
1145                    }
1146                }
1147                break;
1148            default:
1149                break;
1150            }
1151            /*if it's a private arg, just write <priate> to stream*/
1152            if (isPrivacy == 1) {
1153                SecWritePrivateStr(stream, &charsOut);
1154                break;
1155            }
1156
1157            if (noOutput == 0) {
1158                if (formatAttr.flags & SECUREC_FLAG_SIGNED) {
1159                    if (formatAttr.flags & SECUREC_FLAG_NEGATIVE) {
1160                        /* prefix is a '-' */
1161                        prefix[0] = SECUREC_CHAR('-');
1162                        prefixLen = 1;
1163                    } else if (formatAttr.flags & SECUREC_FLAG_SIGN) {
1164                        /* prefix is '+' */
1165                        prefix[0] = SECUREC_CHAR('+');
1166                        prefixLen = 1;
1167                    } else if (formatAttr.flags & SECUREC_FLAG_SIGN_SPACE) {
1168                        /* prefix is ' ' */
1169                        prefix[0] = SECUREC_CHAR(' ');
1170                        prefixLen = 1;
1171                    }
1172                }
1173
1174#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && (!defined(SECUREC_ON_UNIX))
1175                if ((formatAttr.flags & SECUREC_FLAG_POINTER) && (0 == textLen)) {
1176                    formatAttr.flags &= ~SECUREC_FLAG_LEADZERO;
1177                    formatBuf.str = &buffer.str[SECUREC_BUFFER_SIZE - 1];
1178                    *formatBuf.str-- = '\0';
1179                    *formatBuf.str-- = ')';
1180                    *formatBuf.str-- = 'l';
1181                    *formatBuf.str-- = 'i';
1182                    *formatBuf.str-- = 'n';
1183                    *formatBuf.str = '(';
1184                    textLen = 5;
1185                }
1186#endif
1187
1188                /* calculate amount of padding */
1189                padding = (formatAttr.fldWidth - textLen) - prefixLen;
1190
1191                /* put out the padding, prefix, and text, in the correct order */
1192
1193                if (!(formatAttr.flags & (SECUREC_FLAG_LEFT | SECUREC_FLAG_LEADZERO)) && padding > 0) {
1194                    /* pad on left with blanks */
1195                    if (SECUREC_IS_REST_BUF_ENOUGH(padding)) {
1196                        /* char * cast to wchar * */
1197                        SECUREC_SAFE_PADDING(SECUREC_CHAR(' '), padding, stream, &charsOut);
1198                    } else {
1199                        SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR(' '), padding, stream, &charsOut);
1200                    }
1201                }
1202
1203                /* write prefix */
1204                if (prefixLen > 0) {
1205                    SecChar *pPrefix = prefix;
1206                    if (SECUREC_IS_REST_BUF_ENOUGH(prefixLen)) {
1207                        /* max prefix len is 2, use loop copy */ /* char * cast to wchar * */
1208                        SECUREC_SAFE_WRITE_PREFIX(pPrefix, prefixLen, stream, &charsOut);
1209                    } else {
1210                        SECUREC_WRITE_STRING(prefix, prefixLen, stream, &charsOut);
1211                    }
1212                }
1213
1214                if ((formatAttr.flags & SECUREC_FLAG_LEADZERO) && !(formatAttr.flags & SECUREC_FLAG_LEFT)
1215                    && padding > 0) {
1216                    /* write leading zeros */
1217                    if (SECUREC_IS_REST_BUF_ENOUGH(padding)) {
1218                        /* char * cast to wchar * */
1219                        SECUREC_SAFE_PADDING(SECUREC_CHAR('0'), padding, stream, &charsOut);
1220                    } else {
1221                        SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR('0'), padding, stream, &charsOut);
1222                    }
1223                }
1224
1225                /* write text */
1226#ifndef SECUREC_FOR_WCHAR
1227                if (formatAttr.bufferIsWide && (textLen > 0)) {
1228                    wchar_t *p = formatBuf.wStr;
1229                    int count = textLen;
1230                    while (count--) {
1231                        char tmpBuf[SECUREC_MB_LEN + 1];
1232                        SECUREC_MASK_MSVC_CRT_WARNING
1233                        int retVal = wctomb(tmpBuf, *p++);
1234                        SECUREC_END_MASK_MSVC_CRT_WARNING
1235                        if (retVal <= 0) {
1236                            charsOut = -1;
1237                            break;
1238                        }
1239                        SECUREC_WRITE_STRING(tmpBuf, retVal, stream, &charsOut);
1240                    }
1241                } else {
1242                    if (SECUREC_IS_REST_BUF_ENOUGH(textLen)) {
1243                        SECUREC_SAFE_WRITE_STR(formatBuf.str, textLen, stream, &charsOut);
1244                    } else {
1245                        SECUREC_WRITE_STRING(formatBuf.str, textLen, stream, &charsOut);
1246                    }
1247                }
1248#else /* SECUREC_FOR_WCHAR */
1249                if (formatAttr.bufferIsWide == 0 && textLen > 0) {
1250                    int count = textLen;
1251                    char *p = formatBuf.str;
1252
1253                    while (count > 0) {
1254                        wchar_t wchar = L'\0';
1255                        int retVal = mbtowc(&wchar, p, (size_t)MB_CUR_MAX);
1256                        if (retVal <= 0) {
1257                            charsOut = -1;
1258                            break;
1259                        }
1260                        SECUREC_WRITE_CHAR(wchar, stream, &charsOut);
1261                        p += retVal;
1262                        count -= retVal;
1263                    }
1264                } else {
1265                    if (SECUREC_IS_REST_BUF_ENOUGH(textLen)) {
1266                        SECUREC_SAFE_WRITE_STR(formatBuf.wStr, textLen, stream, &charsOut); /* char * cast to wchar * */
1267                    } else {
1268                        SECUREC_WRITE_STRING(formatBuf.wStr, textLen, stream, &charsOut);
1269                    }
1270                }
1271#endif /* SECUREC_FOR_WCHAR */
1272
1273                if (charsOut >= 0 && (formatAttr.flags & SECUREC_FLAG_LEFT) && padding > 0) {
1274                    /* pad on right with blanks */
1275                    if (SECUREC_IS_REST_BUF_ENOUGH(padding)) {
1276                        /* char * cast to wchar * */
1277                        SECUREC_SAFE_PADDING(SECUREC_CHAR(' '), padding, stream, &charsOut);
1278                    } else {
1279                        SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR(' '), padding, stream, &charsOut);
1280                    }
1281                }
1282
1283                /* we're done! */
1284            }
1285            if (floatBuf != NULL) {
1286                SECUREC_FREE(floatBuf);
1287                floatBuf = NULL;
1288            }
1289            break;
1290        case STAT_INVALID:
1291            return -1;
1292        default:
1293            return -1;          /* input format is wrong, directly return */
1294        }
1295    }
1296
1297    if (state != STAT_NORMAL && state != STAT_TYPE) {
1298        return -1;
1299    }
1300
1301    return charsOut;            /* the number of characters written */
1302}                               /* arglist must not be declare as const */
1303#endif /* OUTPUT_P_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 */
1304
1305