#include "SecureCodingUtil.h"


int SafeMemCopy(void *pDestination, int nDestinationSize, const void *pSource, int nSourceSize)
{
    int nResult;
#ifdef __SECURECODING
    nResult = memcpy_s(pDestination, nDestinationSize, pSource, nSourceSize);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESLEMAX:
            return SEC_ERR_SIZE_TOO_BIG;
        case EOVERFLOW:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESNOSPC:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESOVRLP:
            return SEC_ERR_RANGE_OVERLAPPED:
        }
    }
#else
    if (nSourceSize > nDestinationSize)
    {
        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
    }
    if (pSource == NULL || pDestination == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nDestinationSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }
    if (pDestination + nDestinationSize > pSource && pDestination < pSource)
    {
        return SEC_ERR_RANGE_OVERLAPPED;
    }
    if (pSource + nSourceSize > pDestination && pSource < pDestination)
    {
        return SEC_ERR_RANGE_OVERLAPPED;
    }

    memcpy(pDestination, pSource, nSourceSize);
#endif
    return SEC_ERR_SUCCESS;
}

int SafeMemSet(void *pDestination, int nDestinationSize, const char cValue, int nSetSize)
{
    int nResult;
#ifdef __SECURECODING
    nResult = memset_s(pDestination, nDestinationSize, cValue, nSetSize);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESOVRLP:
            return SEC_ERR_RANGE_OVERLAPPED:
        }
    }
#else
    if (nSetSize > nDestinationSize)
    {
        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
    }
    if (pDestination == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nDestinationSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }
    memset(pDestination, cValue, nSetSize);
#endif
    return SEC_ERR_SUCCESS;

}

int SafeStrCmp(const char *pDestination, int nDestinationSize, const char *pSource, int *pnCmpResult)
{
    int nResult;
#ifdef __SECURECODING
    nResult = strcmp_s(pDestination, nDestinationSize, pSource, pnCmpResult);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESUNTERM:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESLEMAX:
            return SEC_ERR_SIZE_TOO_BIG;
        case EOVERFLOW:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        }
    }
#else
//    if (nSourceSize > nDestinationSize)
//    {
//        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
//    }
    if (pSource == NULL || pDestination == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nDestinationSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }

    *pnCmpResult = strcmp(pDestination, pSource);
#endif
    return SEC_ERR_SUCCESS;

}

int SafeStrCat(char *pDestination, int nDestinationSize, const char *pSource, int nSourceSize)
{
    int nResult;
    int nDestinationStringSize;
#ifdef __SECURECODING
    nResult = strncat_s(pDestination, nDestinationSize, pSource, nSourceSize);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESLEMAX:
            return SEC_ERR_SIZE_TOO_BIG;
        case EOVERFLOW:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESUNTERM:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESOVRLP:
            return SEC_ERR_RANGE_OVERLAPPED:
        }
    }
#else
    nDestinationStringSize = strnlen(pDestination, nDestinationSize);
    if (nDestinationStringSize + nSourceSize > nDestinationSize)
    {
        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
    }
    if (pSource == NULL || pDestination == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nDestinationSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }
    if (pDestination + nDestinationSize > pSource && pDestination < pSource)
    {
        return SEC_ERR_RANGE_OVERLAPPED;
    }
    if (pSource + nSourceSize > pDestination && pSource < pDestination)
    {
        return SEC_ERR_RANGE_OVERLAPPED;
    }

    strncat(pDestination, pSource, nSourceSize);
    if (pDestination[nDestinationStringSize + nSourceSize] != '\0')
    {
        printf_s("string doesn't terminated by null!");
        pDestination[nDestinationStringSize + nSourceSize] = '\0';
    }

#endif
    return SEC_ERR_SUCCESS;
}

int SafeStrNCopy(char *pDestination, int nDestinationSize, const char *pSource, int nSourceSize)
{
    int nResult;
#ifdef __SECURECODING
    nResult = strncpy_s(pDestination, nDestinationSize, pSource, nSourceSize);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESLEMAX:
            return SEC_ERR_SIZE_TOO_BIG;
        case EOVERFLOW:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESNOSPC:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESOVRLP:
            return SEC_ERR_RANGE_OVERLAPPED:
        }
    }
#else
    if (nSourceSize > nDestinationSize)
    {
        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
    }
    if (pSource == NULL || pDestination == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nDestinationSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }
    if (pDestination + nDestinationSize > pSource && pDestination < pSource)
    {
        return SEC_ERR_RANGE_OVERLAPPED;
    }
    if (pSource + nSourceSize > pDestination && pSource < pDestination)
    {
        return SEC_ERR_RANGE_OVERLAPPED;
    }

    strncpy(pDestination, pSource, nSourceSize);
    if (pDestination[nSourceSize] != '\0')
    {
        if (nSourceSize > nDestinationSize)
        {
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        }
        else
        {
            pDestination[nSourceSize] = '\0';
        }
    }
#endif
    return SEC_ERR_SUCCESS;
}

int SafeStrCopy(char *pDestination, int nDestinationSize, const char *pSource)
{
    int nResult;
    int nSourceSize;
#ifdef __SECURECODING
    nResult = strcpy_s(pDestination, nDestinationSize, pSource, nSourceSize);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESLEMAX:
            return SEC_ERR_SIZE_TOO_BIG;
        case EOVERFLOW:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESNOSPC:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESOVRLP:
            return SEC_ERR_RANGE_OVERLAPPED:
        }
    }
#else

    nSourceSize = strlen(pSource);
    if (nSourceSize > nDestinationSize)
    {
        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
    }
    if (pSource == NULL || pDestination == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nDestinationSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }
    if (pDestination + nDestinationSize > pSource && pDestination < pSource)
    {
        return SEC_ERR_RANGE_OVERLAPPED;
    }
    if (pSource + nSourceSize > pDestination && pSource < pDestination)
    {
        return SEC_ERR_RANGE_OVERLAPPED;
    }

    strncpy(pDestination, pSource, nDestinationSize);
    pDestination[nSourceSize] = '\0';

#endif
    return SEC_ERR_SUCCESS;
}

int SafeMemCmp(const void *pDestination, int nDestinationSize, const void *pSource, int nSourceSize, int *pnCmpResult)
{
    int nResult;
#ifdef __SECURECODING
    nResult = memcmp_s(pDestination, nDestinationSize, pSource, pnCmpResult);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESUNTERM:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESLEMAX:
            return SEC_ERR_SIZE_TOO_BIG;
        case EOVERFLOW:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        }
    }
#else
    if (nSourceSize > nDestinationSize)
    {
        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
    }
    if (pSource == NULL || pDestination == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nDestinationSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }

    *pnCmpResult = memcmp(pDestination, pSource, nSourceSize);
#endif
    return SEC_ERR_SUCCESS;

}

int SafeStrChr(const char *pSource, int nSourceSize, char cSearchChar, char **pCharPointer)
{
    int nResult;
#ifdef __SECURECODING
    nResult = strchr_s(pSource, nSourceSize, cSearchChar, pCharPointer);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESLEMAX:
            return SEC_ERR_SIZE_TOO_BIG;
        case EOVERFLOW:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESNOSPC:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESOVRLP:
            return SEC_ERR_RANGE_OVERLAPPED;
        case ESNOTFOUND:
            return SEC_ERR_NOT_FOUND;
        }
    }
#else
    if (pSource == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nSourceSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }
    if (CheckNULL(pSource, nSourceSize) != STR_ERR_SUCCESS)
    {
        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
    }

    *pCharPointer = strchr(pSource, cSearchChar);
    if (*pCharPointer == NULL)
    {
        return SEC_ERR_NOT_FOUND;
    }
#endif
    return SEC_ERR_SUCCESS;
}

int SafeStrrChr(const char *pSource, int nSourceSize, char cSearchChar, char **pCharPointer)
{
    int nResult;
#ifdef __SECURECODING
    nResult = strrchr_s(pSource, nSourceSize, cSearchChar, pCharPointer);
    if (nResult != EOK)
    {
        switch (nResult)
        {
        case ESNULLP:
            return SEC_ERR_NULL_PARAMETER;
        case ESZEROL:
            return SEC_ERR_DESTINATION_LEN_ZERO;
        case ESLEMAX:
            return SEC_ERR_SIZE_TOO_BIG;
        case EOVERFLOW:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESNOSPC:
            return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
        case ESOVRLP:
            return SEC_ERR_RANGE_OVERLAPPED;
        case ESNOTFOUND:
            return SEC_ERR_NOT_FOUND;
        }
    }
#else
    if (pSource == NULL)
    {
        return SEC_ERR_NULL_PARAMETER;
    }
    if (nSourceSize == 0)
    {
        return SEC_ERR_DESTINATION_LEN_ZERO;
    }
    if (CheckNULL(pSource, nSourceSize) != STR_ERR_SUCCESS)
    {
        return SEC_ERR_DESTINATION_SIZE_OVERFLOW;
    }

    *pCharPointer = strrchr(pSource, cSearchChar);
    if (*pCharPointer == NULL)
    {
        return SEC_ERR_NOT_FOUND;
    }
#endif
    return SEC_ERR_SUCCESS;
}
