/*********************************************************************************
* Copyright 2019 Huawei Technologies Co.,Ltd.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License.  You may obtain a copy of the
* License at
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations under the License.
**********************************************************************************
*/

#ifndef __SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7
#define __SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7

/*Shielding VC symbol redefinition warning*/
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#ifdef __STDC_WANT_SECURE_LIB__
    #undef __STDC_WANT_SECURE_LIB__
#endif
    #define __STDC_WANT_SECURE_LIB__ 0
#ifdef _CRTIMP_ALTERNATIVE
    #undef _CRTIMP_ALTERNATIVE
#endif
    #define _CRTIMP_ALTERNATIVE //comment microsoft *_s function
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* #include <limits.h> this file is used to define some macros, such as  INT_MAX and SIZE_MAX */

/*if enable COMPATIBLE_WIN_FORMAT, the output format will be compatible to Windows.*/
#if (defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER))
#define COMPATIBLE_WIN_FORMAT
#endif
#if defined(COMPATIBLE_WIN_FORMAT)
/* in windows platform, can't use optimized function for there is no __builtin_constant_p like function */
/* If need optimized macro, can define this: #define __builtin_constant_p(x) 1 */
#ifdef WITH_PERFORMANCE_ADDONS
#undef WITH_PERFORMANCE_ADDONS
#endif
#endif

#if (defined(__VXWORKS__) || defined(__vxworks) || defined(__VXWORKS) || defined(_VXWORKS_PLATFORM_)  || defined(SECUREC_VXWORKS_VERSION_5_4))
#if  !defined(SECUREC_VXWORKS_PLATFORM)
#define SECUREC_VXWORKS_PLATFORM 
#endif
#endif

#ifdef SECUREC_VXWORKS_PLATFORM
#include <version.h>
#endif

/*if enable COMPATIBLE_LINUX_FORMAT, the output format will be compatible to Linux.*/
#if !(defined(COMPATIBLE_WIN_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM))
#define COMPATIBLE_LINUX_FORMAT
#endif
#ifdef COMPATIBLE_LINUX_FORMAT
#include <stddef.h>
#endif

#if defined(__GNUC__)  && !defined(WIN32)
#define SECUREC_ATTRIBUTE(x,y)  __attribute__((format(printf, (x), (y) ))) 
#else
#define SECUREC_ATTRIBUTE(x,y)
#endif

#if defined(__GNUC__) && ((__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3 /*above 3.4*/ ))  ) 
    long __builtin_expect(long exp, long c);
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define LIKELY(x) (x)
#define UNLIKELY(x) (x) 
#endif

#ifndef TWO_MIN
#define TWO_MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

#define WCHAR_SIZE sizeof(wchar_t)

/*ref //sourceforge.net/p/predef/wiki/OperatingSystems/ 
#if !(defined(__hpux) || defined(_AIX) || defined(__VXWORKS__) || defined(__vxworks) ||defined(__ANDROID__) || defined(__WRLINUX__)|| defined(_TYPE_uint8_t))
typedef unsigned char unit8_t;
#endif 
*/ 
typedef signed char INT8T;
typedef unsigned char UINT8T;

#if defined(COMPATIBLE_WIN_FORMAT) || defined(__ARMCC_VERSION)
typedef  __int64 INT64T;
typedef unsigned __int64 UINT64T;
#if defined(__ARMCC_VERSION)
typedef int INT32T;
typedef unsigned int UINT32T;
#else
typedef  __int32 INT32T;
typedef unsigned __int32 UINT32T;
#endif
#else
typedef int INT32T;
typedef unsigned int UINT32T;
typedef long long INT64T;
typedef unsigned long long UINT64T;
#endif

/* define the max length of the string */
#define SECUREC_STRING_MAX_LEN (0x7fffffffUL)
#define SECUREC_WCHAR_STRING_MAX_LEN (SECUREC_STRING_MAX_LEN / WCHAR_SIZE)

/* add SECUREC_MEM_MAX_LEN for memcpy and memmove*/
#define SECUREC_MEM_MAX_LEN (0x7fffffffUL)
#define SECUREC_WCHAR_MEM_MAX_LEN (SECUREC_MEM_MAX_LEN / WCHAR_SIZE)

#if SECUREC_STRING_MAX_LEN > 0x7fffffff
#error "max string is 2G, or you may remove this macro"
#endif

#if (defined(__GNUC__ ) && defined(__SIZEOF_POINTER__ ))
#if (__SIZEOF_POINTER__ != 4) && (__SIZEOF_POINTER__ != 8)
#error "unsupported system, contact Security Design Technology Department of 2012 Labs"
#endif
#endif

#define IN_REGISTER register

#define SECC_MALLOC(x) malloc((size_t)(x))
#define SECC_FREE(x)   free((void *)(x))

#if defined(_WIN64) || defined(WIN64) || defined(__LP64__) || defined(_LP64)
#define SECUREC_ON_64BITS
#endif

#if (!defined(SECUREC_ON_64BITS) && defined(__GNUC__ ) && defined(__SIZEOF_POINTER__ ))
#if __SIZEOF_POINTER__ == 8
#define SECUREC_ON_64BITS
#endif
#endif

#if defined(__SVR4) || defined(__svr4__)
#define __SOLARIS
#endif

#if (defined(__hpux) || defined(_AIX) || defined(__SOLARIS))
#define __UNIX
#endif

#if ((!defined(SECUREC_SUPPORT_STRTOLD)) && defined(COMPATIBLE_LINUX_FORMAT))
#if  defined(__USE_ISOC99)  \
      || (defined(_AIX) && defined(_ISOC99_SOURCE)) \
      || (defined(__hpux) && defined(__ia64)) \
      || (defined(__SOLARIS) &&  (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || defined(_STDC_C99) || defined(__EXTENSIONS__))
#define SECUREC_SUPPORT_STRTOLD
#endif
#endif
#if ((defined(SECUREC_WRLINUX_BELOW4) || defined(_WRLINUX_BELOW4_)) && defined(SECUREC_SUPPORT_STRTOLD))
#undef SECUREC_SUPPORT_STRTOLD
#endif

#if defined(WITH_PERFORMANCE_ADDONS) 
    /* for strncpy_s performance optimization */
#define STRNCPY_SM(dest, destMax, src, count) \
    ((NULL != (void*)dest && NULL != (void*)src && (size_t)destMax >0 && (((UINT64T)(destMax) & (UINT64T)(-2)) < SECUREC_STRING_MAX_LEN) && (TWO_MIN(count , strlen(src)) + 1) <= (size_t)destMax ) ?  ( (count < strlen(src))? (memcpy(dest, src, count), *((char*)dest + count) = '\0', EOK) :( memcpy(dest, src, strlen(src) + 1), EOK ) ) :(strncpy_error(dest, destMax, src, count))  )

#define STRCPY_SM(dest, destMax, src) \
    (( NULL != (void*)dest && NULL != (void*)src  && (size_t)destMax >0 && (((UINT64T)(destMax) & (UINT64T)(-2)) < SECUREC_STRING_MAX_LEN) && ( strlen(src) + 1) <= (size_t)destMax )? (memcpy(dest, src, strlen(src) + 1), EOK) :( strcpy_error(dest, destMax, src)))

   /* for strcat_s performance optimization */
#if defined(__GNUC__)
#define STRCAT_SM(dest, destMax, src) \
    ({ int catRet =EOK;\
    if ( NULL != (void*)dest && NULL != (void*)src && (size_t)(destMax) >0 && (((UINT64T)(destMax) & (UINT64T)(-2)) < SECUREC_STRING_MAX_LEN) ) {\
        char* pCatTmpDst = (dest);\
        size_t catRestSz = (destMax);\
        do{\
            while(catRestSz > 0 && *pCatTmpDst) {\
                ++pCatTmpDst;\
                --catRestSz;\
            }\
            if (catRestSz == 0) {\
                catRet = EINVAL;\
                break;\
            }\
            if ( ( strlen(src) + 1) <= catRestSz ) {\
                memcpy(pCatTmpDst, (src), strlen(src) + 1);\
                catRet = EOK;\
            }else{\
                catRet = ERANGE;\
            }\
        }while(0);\
        if ( EOK != catRet) catRet = strcat_s((dest), (destMax), (src));\
    }else{\
        catRet = strcat_s((dest), (destMax), (src));\
    }\
    catRet;})
#else
#define STRCAT_SM(dest, destMax, src) strcat_s(dest, destMax, src)
#endif

    /*for strncat_s performance optimization*/
#if defined(__GNUC__)
#define STRNCAT_SM(dest, destMax, src, count) \
    ({ int ncatRet = EOK;\
    if (NULL != (void*)dest && NULL != (void*)src && (size_t)destMax > 0 && (((UINT64T)(destMax) & (UINT64T)(-2)) < SECUREC_STRING_MAX_LEN)  && (((UINT64T)(count) & (UINT64T)(-2)) < SECUREC_STRING_MAX_LEN)) {\
        char* pCatTmpDest = (dest);\
        size_t ncatRestSz = (destMax);\
        do{\
            while(ncatRestSz > 0 && *pCatTmpDest) {\
                ++pCatTmpDest;\
                --ncatRestSz;\
            }\
            if (ncatRestSz == 0) {\
                ncatRet = EINVAL;\
                break;\
            }\
            if ( (TWO_MIN((count) , strlen(src)) + 1) <= ncatRestSz ) {\
                if ((count) < strlen(src)) {\
                    memcpy(pCatTmpDest, (src), (count));\
                    *(pCatTmpDest + (count)) = '\0';\
                }else {\
                    memcpy(pCatTmpDest, (src), strlen(src) + 1);\
                }\
            }else{\
                ncatRet = ERANGE;\
            }\
        }while(0);\
        if ( EOK != ncatRet) ncatRet = strncat_s((dest), (destMax), (src), (count));\
    }else{\
        ncatRet = strncat_s((dest), (destMax), (src), (count));\
    }\
    ncatRet;})
#else
#define STRNCAT_SM(dest, destMax, src, count) strncat_s(dest, destMax, src, count)
#endif

    /*
    MEMCPY_SM do NOT check buffer overlap by default, or you can add this check to improve security
    condCheck = condCheck || (dest == src) || (dest > src && dest < (void*)((UINT8T*)src + count));\
    condCheck = condCheck || (src > dest && src < (void*)((UINT8T*)dest + count)); \
    */

#define  MEMCPY_SM(dest, destMax, src, count)\
    (!(((size_t)destMax== 0 )||(((UINT64T)(destMax) & (UINT64T)(-2)) > SECUREC_MEM_MAX_LEN)||((size_t)count > (size_t)destMax) || (NULL == (void*)dest) || (NULL == (void*)src))? (memcpy(dest, src, count), EOK) : (memcpy_s(dest, destMax, src, count)))

#define  MEMSET_SM(dest, destMax, c, count)\
    (!(((size_t)destMax == 0 ) || (((UINT64T)(destMax) & (UINT64T)(-2)) > SECUREC_MEM_MAX_LEN) || (NULL == (void*)dest) || ((size_t)count > (size_t)destMax)) ? (memset(dest, c, count), EOK) : ( memset_s(dest, destMax, c, count)))

#endif /* WITH_PERFORMANCE_ADDONS */

/* 20150105 For software and hardware decoupling,such as UMG*/
#ifdef SECUREC_SYSAPI4VXWORKS
#ifdef feof
#undef feof
#endif
extern int feof(FILE *stream);

#ifndef isspace
#define isspace(c)      (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n'))
#endif
#ifndef isascii
#define isascii(c)       (((unsigned char)(c))<=0x7f)
#endif
#ifndef isupper
#define isupper(c)       ((c) >= 'A' && (c) <= 'Z')
#endif
#ifndef islower
#define islower(c)       ((c) >= 'a' && (c) <= 'z')
#endif
#ifndef isalpha
#define isalpha(c)       (isupper(c) || (islower(c)))
#endif
#ifndef isdigit
#define isdigit(c)       ((c) >= '0' && (c) <= '9')
#endif
#ifndef isxdigit
#define isxupper(c)      ((c) >= 'A' && (c) <= 'F')
#define isxlower(c)      ((c) >= 'a' && (c) <= 'f')
#define isxdigit(c)      (isdigit(c) || isxupper(c) ||isxlower(c))
#endif
#endif

#endif    /*__SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7*/


