/*#include <stdlib.h>
#include <libsafec/safe_str_lib.h>
#include <libsafec/safe_lib_errno.h>
#include <ctype.h>
#include <limits.h>
#include "Common.h"
*/
#include "StringUtil.h"

pthread_mutex_t g_sStringUtilMutex = PTHREAD_MUTEX_INITIALIZER;


// 문자열을 한번만 검색하면서 모든것을 결정하려고 하는데 실제로 더 빠를까?(if문이 많아져서 더 느리진 않을까?)
int Trim(char *szDesc, int nMaxLength, const char *szSrc)
{
    int nDataStartPos;          // don't include space
    int nDataEndPos;            // don't include space
    int nEndPos;                // Include space
    bool bFindFirstChar;
    int nResult;
    
    if (szDesc == NULL)
    {
        return STR_ERR_NULL_PARAMETER;
    }
    
    if (szSrc == NULL)
    {
        return STR_ERR_NULL_PARAMETER;
    }
    
    if (nMaxLength == 0)
    {
        return STR_ERR_SIZE_ZERO;
    }
    
    bFindFirstChar = false;
    nDataStartPos = 0;
    nDataEndPos = -1;
    for (nEndPos = 0;szSrc[nEndPos] != '\0' && nEndPos < nMaxLength;nEndPos++)
    {
        if (!isspace(szSrc[nEndPos]))
        {
            if (!bFindFirstChar)
            {
                bFindFirstChar = true;
                nDataStartPos = nEndPos;
            }
            nDataEndPos = nEndPos;
        }
    }
    if (nDataEndPos == -1)
    {
        nDataEndPos = nEndPos;
    }
    SafeStrNCopy(szDesc, nMaxLength, szSrc + nDataStartPos, nDataEndPos - nDataStartPos + 1);
    
    return STR_ERR_SUCCESS;
}

// 문자열을 한번만 검색하면서 모든것을 결정하려고 하는데 실제로 더 빠를까?(if문이 많아져서 더 느리진 않을까?)
int RTrim(char *szDesc, int nMaxLength, const char *szSrc)
{
    int nDataEndPos;            // don't include space
    int nEndPos;                // Include space
    int nResult;
    
    if (szDesc == NULL)
    {
        return STR_ERR_NULL_PARAMETER;
    }
    
    if (szSrc == NULL)
    {
        return STR_ERR_NULL_PARAMETER;
    }
    
    if (nMaxLength == 0)
    {
        return STR_ERR_SIZE_ZERO;
    }
    
    nDataEndPos = -1;
    for (nEndPos = 0;szSrc[nEndPos] != '\0' && nEndPos < nMaxLength;nEndPos++)
    {
        if (!isspace(szSrc[nEndPos]))
        {
            nDataEndPos = nEndPos;
        }
    }
    if (nDataEndPos == -1)
    {
        nDataEndPos = nEndPos;
    }
    SafeStrNCopy(szDesc, nMaxLength, szSrc, nDataEndPos + 1);
    
    return STR_ERR_SUCCESS;
}

// 문자열을 한번만 검색하면서 모든것을 결정하려고 하는데 실제로 더 빠를까?(if문이 많아져서 더 느리진 않을까?)
int LTrim(char *szDesc, int nMaxLength, const char *szSrc)
{
    int nDataStartPos;          // don't include space
    int nEndPos;                // Include space
    bool bFindFirstChar;
    int nResult;
    
    if (szDesc == NULL)
    {
        return STR_ERR_NULL_PARAMETER;
    }
    
    if (szSrc == NULL)
    {
        return STR_ERR_NULL_PARAMETER;
    }
    
    if (nMaxLength == 0)
    {
        return STR_ERR_SIZE_ZERO;
    }
    
    bFindFirstChar = false;
    nDataStartPos = 0;
    for (nEndPos = 0;szSrc[nEndPos] != '\0' && nEndPos < nMaxLength;nEndPos++)
    {
        if (!isspace(szSrc[nEndPos]))
        {
            if (!bFindFirstChar)
            {
                bFindFirstChar = true;
                nDataStartPos = nEndPos;
            }
        }
    }

    SafeStrNCopy(szDesc, nMaxLength, szSrc + nDataStartPos,nEndPos - nDataStartPos + 1);
    
    return STR_ERR_SUCCESS;
}

/*
int SafeStringToInt(const char * szStringNumber, int nStringLength, int *pnValue)
{
    char *pEndPoint;
    char szStringTemp[MAX_STRING_SIZE + 1];
    long nLongValue;

    errno = 0;
    strcpy_s(szStringTemp, (sizeof(szStringTemp) > nStringLength)? nStringLength : sizeof(szStringTemp) , szStringNumber);
    nLongValue = strtol(szStringNumber, &pEndPoint, 10);
    if (errno == ERANGE)
    {
        return STR_ERR_OVERFLOW;
    }
    if (errno != 0)
    {
        return STR_ERR_UNKNOWN;
    }
    if (pEndPoint == (char *)NULL)
    {
        return STR_ERR_NONNUMERIC;
    }
    if (*pEndPoint != '\0')
    {
        return STR_ERR_NONNUMERIC;
    }
    if (isspace(*szStringNumber))
    {
        return STR_ERR_NONNUMERIC;
    }
    if (nLongValue > INT_MIN || nLongValue < INT_MAX)
    {
        return STR_ERR_OVERFLOW;
    }
    *pnValue =  nLongValue;
    return EOK;
}
*/

int SafeStringToIntWithBase(const char * szStringNumber, int nStringLength, long *pnValue, int nBase)
{
    char *pEndPoint;
    char szStringTemp[MAX_STRING_SIZE + 1];
    long nLongValue;

    errno = 0;
    //strcpy_s(szStringTemp, sizeof(szStringTemp) , szStringNumber);
    SafeMemCopy(szStringTemp, sizeof(szStringTemp), szStringNumber, nStringLength);
    szStringTemp[nStringLength] = '\0';
    nLongValue = strtol(szStringTemp, &pEndPoint, nBase);
    if (errno == ERANGE)
    {
        return STR_ERR_OVERFLOW;
    }
    if (errno != 0)
    {
        return STR_ERR_UNKNOWN;
    }
    if (pEndPoint == (char *)NULL)
    {
        return STR_ERR_NONNUMERIC;
    }
    if (*pEndPoint != '\0')
    {
        return STR_ERR_NONNUMERIC;
    }
    if (isspace(*szStringNumber))
    {
        return STR_ERR_NONNUMERIC;
    }
    if (nLongValue < INT_MIN || nLongValue > INT_MAX)
    {
        return STR_ERR_OVERFLOW;
    }
    *pnValue =  nLongValue;
    return STR_ERR_SUCCESS;
}

int SafeStringToInt(const char * szStringNumber, int nStringLength, int *pnValue)
{
    long nLongValue;
    int nResult;

    nResult = SafeStringToIntWithBase(szStringNumber, nStringLength, &nLongValue, 10);
    *pnValue = nLongValue;
    return nResult;
}

int SafeStringToLong(const char * szStringNumber, int nStringLength, long *pnValue)
{
    long nLongValue;
    int nResult;

    nResult = SafeStringToIntWithBase(szStringNumber, nStringLength, &nLongValue, 10);
    *pnValue = nLongValue;
    return nResult;
}


int SafeHexStringToInt(const char * szStringNumber, int nStringLength, uint16_t *pnValue)
{
    long nLongValue;
    int nResult;

    nResult= SafeStringToIntWithBase(szStringNumber, nStringLength, &nLongValue, 16);
    *pnValue = nLongValue;
    return nResult;
}
// malloc의 경우 size가 0으로 할당되는 경우에 되어 정의되어 있지 않다.
// 포인트 변수가 NULL 인 경우에만 할당 하게 수정 필요
int SafeMemoryAlloc(void **pData, size_t nSize)
{
    pthread_mutex_lock(&g_sStringUtilMutex);
    if (*pData != NULL)
    {
        WriteTraceLog(LogType_ErrorOut, LogLevel_Error, __FILE__, __LINE__, __FUNCTION__, "Memory Reallocation");
        pthread_mutex_unlock(&g_sStringUtilMutex);
        return STR_ERR_NOT_NULL;
    }

    if (nSize == 0)
    {
        pthread_mutex_unlock(&g_sStringUtilMutex);
        return STR_ERR_SIZE_ZERO;
    }
    *pData = malloc(nSize);
    if (*pData == NULL)
    {
        WriteLog(LogType_ErrorOut, LogLevel_Error, __FILE__, __LINE__, __FUNCTION__, "Out of memory");
        pthread_mutex_unlock(&g_sStringUtilMutex);
        return STR_ERR_NO_MEM;
    }
    pthread_mutex_unlock(&g_sStringUtilMutex);
    return STR_ERR_SUCCESS;
}

//void *SafeAlloc(void *pData, size_t nSize)
//{
//    void *pNewAlloc;
//
//
//    if (pData != NULL)
//    {
//        WriteLog(LogType_ErrorOut, LogLevel_Error, "Memory Reallocation");
//        return pData;
//    }
//
//    if (nSize == 0)
//    {
//        return NULL;
//    }
//    pNewAlloc = malloc(nSize);
//    if (pNewAlloc == NULL)
//    {
//        WriteLog(LogType_ErrorOut, LogLevel_Error, "Out of memory");
//    }
//    return pNewAlloc;
//}


void SafeFree(void **pData)
{
#if 0 //오류 확인을 위한 로그
proc_log("Mutex[%x][%x][%x]\n", g_sStringUtilMutex, &g_sStringUtilMutex, *pData);
#endif
    pthread_mutex_lock(&g_sStringUtilMutex);
    if (pData == NULL)
    {
        pthread_mutex_unlock(&g_sStringUtilMutex);
        return;
    }
    if (*pData == NULL)
    {
        pthread_mutex_unlock(&g_sStringUtilMutex);
        return;
    }
    free(*pData);
    *pData = NULL;
    pthread_mutex_unlock(&g_sStringUtilMutex);
}

int GetCheckedValue(int nType, char *szCheckedValue, int nCheckedValueSize, const char *pData)
{
    int nIndex;
    int nNullIndex;
    int nYear;
    int nMonth;
    int nDay;
    int nHour;
    int nMinute;
    int nSecond;
    int nMiliSecond;
    int nConvertResult;
    int nCheckedValueIndex;

    /* Date Check Range
     * Year         : 1900 ~ 2200
     * Month        : 1 ~ 12
     * Day          : 1 ~ 31
     */
    /* Time Check Range
     * Hour         : 0 ~ 23
     * Minute       : 0 ~ 59
     * Second       : 0 ~ 59
     * MiliSecond   : 0 ~ 999
     */

    nNullIndex = -1;
    nCheckedValueIndex = 0;
    for (nIndex = 0; nIndex < nCheckedValueSize; nIndex++)
    {
        if (pData[nIndex] == '\0')
        {
            nNullIndex = nIndex;
            break;
        }
        switch (nType)
        {
        case TYPE_YN:
            if (pData[nIndex] != 'Y' && pData[nIndex] != 'y' && pData[nIndex] != 'N' && pData[nIndex] != 'n')
                return STR_ERR_FAIL_TYPE;
            if (nCheckedValueSize != 1)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DIGIT:                       // Character로 표시된 문자형태 "0100" : 단 10진수 형태의 사용만
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_ALPHA:                       // 영문으로 표시된 문자형태(TODO : 한글 별도로 체크 해야 되는지? isalpha로 체크 되는지 확인 필요)
            if (isalpha(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_ALPHA_NUMERIC:               // TYPE_DIGIT || TYPE_ALPHA
            if (isalnum(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_HEX:                         // 16진수 문자열 확인
            if (isxdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_BCD:                         // BCD 바이너리를 만족하는지 확인(BCD 텍스트로 해야할지 고민중)
            if (isxdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_FILENAME:                    // 확장자나 특수 문자등 print 가능한 문자여부를 확인 함
            if (isprint(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DATE8:                       // YYYYMMDD
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DATE6:                       // YYMMDD
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_TIME6:                       // HHMMSS
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_TIME9:                       // HHMMSSFFF
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DTIME12:                     // YYMMDDHHMMSS
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DTIME14:                     // YYYYMMDDHHMMSS
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DTIME17:                     // YYYYMMDDHHMMSSFFF
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        default:
            return STR_ERR_TYPE_UNKNOWN;
        }
        if (isspace(pData[nIndex]) == 0)
        {
            szCheckedValue[nCheckedValueIndex++] = pData[nIndex];
        }
    }
    if (nNullIndex == -1)
    {
        nNullIndex = nIndex;
        szCheckedValue[nIndex] = '\0';
    }

switch (nType)
    {
    case TYPE_YN:
    case TYPE_DIGIT:                       // Character로 표시된 문자형태 "0100" : 단 10진수 형태의 사용만
    case TYPE_ALPHA:                       // 영문으로 표시된 문자형태(TODO : 한글 별도로 체크 해야 되는지? isalpha로 체크 되는지 확인 필요)
    case TYPE_ALPHA_NUMERIC:               // TYPE_DIGIT || TYPE_ALPHA
    case TYPE_HEX:                         // 16진수 문자열 확인
    case TYPE_BCD:                         // BCD 바이너리를 만족하는지 확인(BCD 텍스트로 해야할지 고민중)
    case TYPE_FILENAME:
        break;
    case TYPE_DATE8:                       // YYYYMMDD
        if (nNullIndex != 8)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 4, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_DATE6:                       // YYMMDD
        if (nNullIndex != 6)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 2, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nYear = nYear + STR_SHORT_DATE_BASE;
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_TIME6:                       // HHMMSS
        if (nNullIndex != 6)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 2, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_TIME9:                       // HHMMSSFFF
        if (nNullIndex != 9)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 2, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 3, &nMiliSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMiliSecond < STR_MILISECOND_MIN || nMiliSecond > STR_MILISECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_DTIME12:                     // YYMMDDHHMMSS
        if (nNullIndex != 12)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 2, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nYear = nYear + STR_SHORT_DATE_BASE;
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 8, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 10, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_DTIME14:                     // YYYYMMDDHHMMSS
        if (nNullIndex != 14)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 4, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue + 8, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 10, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 12, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_DTIME17:                     // YYYYMMDDHHMMSSFFF
        if (nNullIndex != 17)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 4, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue + 8, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 10, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 12, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 14, 3, &nMiliSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMiliSecond < STR_MILISECOND_MIN || nMiliSecond > STR_MILISECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    default:
        return STR_ERR_TYPE_UNKNOWN;
    }
    return STR_ERR_SUCCESS;
}

int GetCheckedValueEndWithSep(int nType, char *szCheckedValue, int nCheckedValueSize, const char *pData, int *pnDataSize, char cSeperator)
{
    int nIndex;
    int nNullIndex;
    int nYear;
    int nMonth;
    int nDay;
    int nHour;
    int nMinute;
    int nSecond;
    int nMiliSecond;
    int nConvertResult;
    int nCheckedValueIndex;

    /* Date Check Range
     * Year         : 1900 ~ 2200
     * Month        : 1 ~ 12
     * Day          : 1 ~ 31
     */
    /* Time Check Range
     * Hour         : 0 ~ 23
     * Minute       : 0 ~ 59
     * Second       : 0 ~ 59
     * MiliSecond   : 0 ~ 999
     */
    nNullIndex = -1;
    nCheckedValueIndex = 0;
    for (nIndex = 0; nIndex < nCheckedValueSize && pData[nIndex] != cSeperator; nIndex++)
    {
        if (pData[nIndex] == '\0')
        {
            nNullIndex = nIndex;
            break;
        }
        switch (nType)
        {
        case TYPE_YN:
            if (pData[nIndex] != 'Y' && pData[nIndex] != 'y' && pData[nIndex] != 'N' && pData[nIndex] != 'n')
                return STR_ERR_FAIL_TYPE;
            if (pData[nIndex + 1] != cSeperator)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DIGIT:                       // Character로 표시된 문자형태 "0100" : 단 10진수 형태의 사용만
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_ALPHA:                       // 영문으로 표시된 문자형태(TODO : 한글 별도로 체크 해야 되는지? isalpha로 체크 되는지 확인 필요)
            if (isalpha(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_ALPHA_NUMERIC:               // TYPE_DIGIT || TYPE_ALPHA
            if (isalnum(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_HEX:                         // 16진수 문자열 확인
            if (isxdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_BCD:                         // BCD 바이너리를 만족하는지 확인(BCD 텍스트로 해야할지 고민중)
            if (isxdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_FILENAME:                    // 확장자나 특수 문자등 print 가능한 문자여부를 확인 함
            if (isprint(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DATE8:                       // YYYYMMDD
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DATE6:                       // YYMMDD
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_TIME6:                       // HHMMSS
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_TIME9:                       // HHMMSSFFF
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DTIME12:                     // YYMMDDHHMMSS
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DTIME14:                     // YYYYMMDDHHMMSS
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        case TYPE_DTIME17:                     // YYYYMMDDHHMMSSFFF
            if (isdigit(pData[nIndex]) == 0)
                return STR_ERR_FAIL_TYPE;
            break;
        default:
            return STR_ERR_TYPE_UNKNOWN;
        }
        if (isspace(pData[nIndex]) == 0)
        {
            szCheckedValue[nCheckedValueIndex++] = pData[nIndex];
        }
    }
    *pnDataSize = nIndex;
    if (nNullIndex == -1)
    {
        nNullIndex = nIndex;
    }
    // 아래 문자열 길이 체크에 nNullIndex -> nCheckedValueIndex로 변경 필요
    szCheckedValue[nIndex] = '\0';
    switch (nType)
    {
    case TYPE_YN:
    case TYPE_DIGIT:                       // Character로 표시된 문자형태 "0100" : 단 10진수 형태의 사용만
    case TYPE_ALPHA:                       // 영문으로 표시된 문자형태(TODO : 한글 별도로 체크 해야 되는지? isalpha로 체크 되는지 확인 필요)
    case TYPE_ALPHA_NUMERIC:               // TYPE_DIGIT || TYPE_ALPHA
    case TYPE_HEX:                         // 16진수 문자열 확인
    case TYPE_BCD:                         // BCD 바이너리를 만족하는지 확인(BCD 텍스트로 해야할지 고민중)
    case TYPE_FILENAME:                    // 확장자나 특수 문자등 print 가능한 문자여부를 확인 함
        break;
    case TYPE_DATE8:                       // YYYYMMDD
        if (nNullIndex != 8)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 4, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_DATE6:                       // YYMMDD
        if (nNullIndex != 6)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 2, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nYear = nYear + STR_SHORT_DATE_BASE;
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_TIME6:                       // HHMMSS
        if (nNullIndex != 6)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 2, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_TIME9:                       // HHMMSSFFF
        if (nNullIndex != 9)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 2, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 3, &nMiliSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMiliSecond < STR_MILISECOND_MIN || nMiliSecond > STR_MILISECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_DTIME12:                     // YYMMDDHHMMSS
        if (nNullIndex != 12)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 2, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nYear = nYear + STR_SHORT_DATE_BASE;
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 8, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 10, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_DTIME14:                     // YYYYMMDDHHMMSS
        if (nNullIndex != 14)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 4, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue + 8, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 10, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 12, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    case TYPE_DTIME17:                     // YYYYMMDDHHMMSSFFF
        if (nNullIndex != 17)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue, 2, &nYear);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 4, 2, &nMonth);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 6, 2, &nDay);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nYear < STR_YEAR_MIN || nYear > STR_YEAR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMonth < STR_MONTH_MIN || nMonth > STR_MONTH_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nDay < STR_DAY_MIN || nDay > STR_DAY_MAX)
            return STR_ERR_FAIL_TYPE;
        nConvertResult = SafeStringToInt(szCheckedValue + 8, 2, &nHour);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 10, 2, &nMinute);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 12, 2, &nSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        nConvertResult = SafeStringToInt(szCheckedValue + 14, 3, &nMiliSecond);
        if (nConvertResult != STR_ERR_SUCCESS)
        {
            return STR_ERR_FAIL_TYPE;
        }
        if (nHour < STR_HOUR_MIN || nHour > STR_HOUR_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMinute < STR_MINUTE_MIN || nMinute > STR_MINUTE_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nSecond < STR_SECOND_MIN || nSecond > STR_SECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        if (nMiliSecond < STR_MILISECOND_MIN || nMiliSecond > STR_MILISECOND_MAX)
            return STR_ERR_FAIL_TYPE;
        break;
    default:
        return STR_ERR_TYPE_UNKNOWN;
    }
    return STR_ERR_SUCCESS;
}


int CheckNULL(const char *pszData, int nDataLen)
{
    int nOffset;

    for (nOffset = nDataLen; nOffset >= 0; nOffset--)
    {
        if (pszData[nOffset] == '\0')
            return STR_ERR_SUCCESS;
    }
    return STR_ERR_NOT_EXIST_NULL;
}

int GetCurrTime(struct tm *pTM, int *pnMilliSec)
{
    struct timespec sTimeSpec;
    time_t sNow;

    if (pTM == NULL || pnMilliSec == NULL)
    {
        WriteTraceLog(LogType_ErrorOut, LogLevel_Trace, __FILE__, __LINE__, __FUNCTION__, "Null parameter error");
        return STR_ERR_NULL_PARAMETER;
    }

    clock_gettime(CLOCK_REALTIME, &sTimeSpec);
    sNow = sTimeSpec.tv_sec;
    *pnMilliSec = sTimeSpec.tv_nsec / 1.0e6; // nanoseconds to milliseconds
#ifdef _WIN32
    if (localtime_s(pTM, &sNow) != 0)
#else
    if (localtime_r(&sNow, pTM) == NULL)
#endif
    {
        WriteTraceLog(LogType_ErrorOut, LogLevel_Trace, __FILE__, __LINE__, __FUNCTION__, "localtime_r error");
        return STR_ERR_UNKNOWN;
    }
    return STR_ERR_SUCCESS;
}

int GetDateTimeString(int nType, char *pszDateTimeString, int nDateTimeSize)
{
    struct tm sTM;
    int nMilliSec;
    int nResult;

    nResult = GetCurrTime(&sTM, &nMilliSec);
    if (nResult != STR_ERR_SUCCESS)
    {
        return STR_ERR_UNKNOWN;
    }

    switch(nType)
    {
    case TYPE_DATE8:                       // YYYYMMDD
        if (nDateTimeSize < 9)
        {
            return STR_ERR_VARIABLE_TOO_SHORT;
        }
        snprintf(pszDateTimeString, 9, "%04d%02d%02d", sTM.tm_year + 1900, sTM.tm_mon + 1, sTM.tm_mday);
        pszDateTimeString[8] = '\0';
        break;
    case TYPE_DATE6:                       // YYMMDD
        if (nDateTimeSize < 7)
        {
            return STR_ERR_VARIABLE_TOO_SHORT;
        }
        snprintf(pszDateTimeString, 7, "%02d%02d%02d", (sTM.tm_year + 1900) % 100, sTM.tm_mon + 1, sTM.tm_mday);
        pszDateTimeString[6] = '\0';
        break;
    case TYPE_TIME6:                       // HHMMSS
        if (nDateTimeSize < 7)
        {
            return STR_ERR_VARIABLE_TOO_SHORT;
        }
        snprintf(pszDateTimeString, 7, "%02d%02d%02d", sTM.tm_hour, sTM.tm_min, sTM.tm_sec);
        pszDateTimeString[6] = '\0';
        break;
    case TYPE_TIME9:                       // HHMMSSFFF
        if (nDateTimeSize < 10)
        {
            return STR_ERR_VARIABLE_TOO_SHORT;
        }
        snprintf(pszDateTimeString, 10, "%02d%02d%02d%03d", sTM.tm_hour, sTM.tm_min, sTM.tm_sec, nMilliSec);
        pszDateTimeString[9] = '\0';
        break;
    case TYPE_DTIME12:                     // YYMMDDHHMMSS
        if (nDateTimeSize < 13)
        {
            return STR_ERR_VARIABLE_TOO_SHORT;
        }
        snprintf(pszDateTimeString, 13, "%02d%02d%02d%02d%02d%02d", (sTM.tm_year + 1900) % 100, sTM.tm_mon + 1, sTM.tm_mday, sTM.tm_hour, sTM.tm_min, sTM.tm_sec);
        pszDateTimeString[12] = '\0';
        break;
    case TYPE_DTIME14:                     // YYYYMMDDHHMMSS
        if (nDateTimeSize < 15)
        {
            return STR_ERR_VARIABLE_TOO_SHORT;
        }
        snprintf(pszDateTimeString, 15, "%04d%02d%02d%02d%02d%02d", sTM.tm_year + 1900, sTM.tm_mon + 1, sTM.tm_mday, sTM.tm_hour, sTM.tm_min, sTM.tm_sec);
        pszDateTimeString[14] = '\0';
        break;
    case TYPE_DTIME17:                     // YYYYMMDDHHMMSSFFF
        if (nDateTimeSize < 18)
        {
            return STR_ERR_VARIABLE_TOO_SHORT;
        }
        snprintf(pszDateTimeString, 18, "%04d%02d%02d%02d%02d%02d%03d", sTM.tm_year + 1900, sTM.tm_mon + 1, sTM.tm_mday, sTM.tm_hour, sTM.tm_min, sTM.tm_sec, nMilliSec);
        pszDateTimeString[17] = '\0';
        break;
    default:
        return STR_ERR_TYPE_UNKNOWN;
    }
    return STR_ERR_SUCCESS;
}

int CalculateIntRemainder(int nValue, int nBase, int nDigitCount)
{
    return nValue % (int)(pow(nBase, nDigitCount));
}
