#include "remvar.h" #include "conv.h" #define _IS_VALID_VT(vt) ((vt > CRemStringVariable::VT_Invalid) && (vt < CRemStringVariable::VT_Last)) #define __min(x, y) ((x) < (y) ? (x) : (y)) #define __max(x, y) ((x) > (y) ? (x) : (y)) ///////////////////////////////////////////////////////////////////////////// CRemStringVariable::CRemStringVariable(void *pData, size_t nCChData, VT vt, const std::type_info &rti, HSHM hShm, bool bIsDbPersitent, const char *pszName, int nIndex, CRemanent *pParent) : m_name(pszName), m_pszPath(NULL), m_nIndex(nIndex), m_vt(VT_Invalid), m_data({NULL}), m_cache({NULL}), m_nCbString(0), m_pParent(pParent), m_nUpdates(0), m_bMustLog(false), m_bIsDbPersitent(bIsDbPersitent), m_nCbVarpath(0), m_nCbLog(0) { if(!pData || !hShm || !nCChData || !_IS_VALID_VT(vt)) { ASSERT(false); return; } m_vt = vt; m_data.pVoid = pData; m_hShm = hShm; memset(m_szLog, 0, sizeof(m_szLog)); if( (rti == typeid(char)) || (rti == typeid(signed char)) || (rti == typeid(unsigned char))) { switch(vt) { case VT_Latin1: case VT_UTF_8: m_nCbBuffer = nCChData; m_cache.pVoid = ::malloc(m_nCbBuffer); zeroTerm(m_data, nCChData - 1); memcpy(m_cache.pVoid, m_data.pVoid, m_nCbBuffer); m_nCbString = strlen(m_cache.pszMbs); break; case VT_UTF_16: case VT_UTF_32: case VT_Unicode: ASSERT(false); return; default: ASSERT(false); return; } } else if(rti == typeid(char16_t)) { switch(vt) { case VT_UTF_16: m_nCbBuffer = nCChData * sizeof(char16_t); m_cache.pVoid = malloc(m_nCbBuffer); zeroTerm(m_data, nCChData - 1); memcpy(m_cache.pVoid, m_data.pVoid, m_nCbBuffer); m_nCbString = wcs16len(m_cache.pszWc16) * sizeof(char16_t); break; case VT_Unicode: case VT_Latin1: case VT_UTF_8: case VT_UTF_32: ASSERT(false); return; default: ASSERT(false); return; } } else if(rti == typeid(char32_t)) { switch(vt) { case VT_UTF_32: m_nCbBuffer = nCChData * sizeof(char32_t); m_cache.pVoid = malloc(m_nCbBuffer); zeroTerm(m_data, nCChData - 1); memcpy(m_cache.pVoid, m_data.pVoid, m_nCbBuffer); m_nCbString = wcs32len(m_cache.pszWc32) * sizeof(char32_t); break; case VT_Unicode: case VT_Latin1: case VT_UTF_8: case VT_UTF_16: ASSERT(false); return; default: ASSERT(false); return; } } else if(rti == typeid(wchar_t)) { switch(vt) { case VT_Unicode: m_nCbBuffer = nCChData * sizeof(wchar_t); m_cache.pVoid = malloc(m_nCbBuffer); zeroTerm(m_data, nCChData - 1); memcpy(m_cache.pVoid, m_data.pVoid, m_nCbBuffer); m_nCbString = wcslen(m_cache.pszWcs) * sizeof(wchar_t); break; case VT_Latin1: case VT_UTF_8: case VT_UTF_16: case VT_UTF_32: ASSERT(false); return; default: ASSERT(false); return; } } else { ASSERT(false); } } CRemStringVariable::~CRemStringVariable(void) { } ///////////////////////////////////////////////////////////////////////////// void CRemStringVariable::InitPath(CRemanent *pParent, const char *pszMemberName) { if(!pszMemberName) pszMemberName = ""; if(pParent) { m_path = pParent->GetPath(); if(m_path.size() > 0) m_path += "/"; m_path += pszMemberName; if(m_nIndex >= 0) { char szIndex[32]; sprintf(szIndex, "[%d]", m_nIndex); m_path += szIndex; } } else { m_path = pszMemberName; } m_pszPath = m_path.c_str(); m_nCbVarpath = m_path.length(); } #if 0 static int _fnprintf(FILE *f, size_t n, const char * format, ...) { if(!n) return 0; int nRet; char *pszBuffer = malloc(n); va_list args; va_start (args, format); nRet = vsnprintf(pszBuffer, n, format, args); va_end (args); if(nRet > 0) nRet = (int)fwrite(pszBuffer, nRet, 1, f); free(pszBuffer); return nRet; } #endif bool CRemStringVariable::SaveJSON(FILE *f, int nIndent, bool bValueOnly, bool bWriteComma) { if(m_bIsDbPersitent) return true; size_t nToWrite; if(bWriteComma) { if(fprintf(f, ",") < 0) return false; } if(!bValueOnly) { if(fprintf(f, "\n") < 0) return false; if(nIndent > 0) { if(fprintf(f, "%*s", nIndent * _JSON_SPACES_PER_TAB, "") < 0) return false; } if(fprintf(f, "\"%s\": ", m_name.c_str()) < 0) return false; } switch(m_vt) { case VT_Latin1: case VT_UTF_8: if(fputc('\"', f) == EOF) return false; nToWrite = _MIN(m_nCbString, (m_nCbBuffer - 1)); if(fwrite(m_cache.pszMbs, 1, nToWrite, f) != nToWrite) return false; if(fputc('\"', f) == EOF) return false; break; default: break; } return true; } void CRemStringVariable::CreateMembersTable(CRemVarTable &vt) { if(!m_bIsDbPersitent) vt.AddVar(static_cast(this)); } bool CRemStringVariable::SetJSONValue(const Json::Value &jv, bool fLock) { if(jv.type() != Json::stringValue) return false; const char *pszStr = jv.asCString(); if(!pszStr || !*pszStr) { memset(m_cache.pVoid, 0, m_nCbBuffer); if(fLock) Lock(); memset(m_data.pVoid, 0, m_nCbBuffer); if(fLock) Unlock(); return true; } size_t nLen = strlen(pszStr); switch(m_vt) { case VT_Latin1: Utf8ToLatin1(pszStr, nLen, m_cache.pszMbs, m_nCbBuffer); m_nCbString = strlen(m_cache.pszMbs); break; case VT_UTF_8: if(nLen >= m_nCbBuffer) nLen = m_nCbBuffer - 1; memset(m_cache.pszMbs, 0, m_nCbBuffer); memcpy(m_cache.pszMbs, pszStr, nLen); m_nCbString = nLen; break; case VT_UTF_16: Utf8ToUtf16(pszStr, nLen, m_cache.pszWc16, m_nCbBuffer / sizeof(char16_t)); m_nCbString = wcs16len(m_cache.pszWc16) * sizeof(char16_t); break; case VT_UTF_32: Utf8ToUtf32(pszStr, nLen, m_cache.pszWc32, m_nCbBuffer / sizeof(char32_t)); m_nCbString = wcs32len(m_cache.pszWc32) * sizeof(char32_t); break; case VT_Unicode: Utf8ToWcs(pszStr, nLen, m_cache.pszWcs, m_nCbBuffer / sizeof(wchar_t)); m_nCbString = wcslen(m_cache.pszWcs) * sizeof(wchar_t); break; default: return false; } if(fLock) Lock(); memcpy(m_data.pVoid, m_cache.pVoid, m_nCbBuffer); if(fLock) Unlock(); return true; } unsigned long long CRemStringVariable::CheckUpdateShm(bool fLock) { CHECK_UPDATE_SHM_RETVAL rv = {1, 0}; if(m_bIsDbPersitent) return rv.nRetval; size_t nCChBuf = 0; if(fLock) Lock(); if(shmChanged(false)) { switch(m_vt) { case VT_Latin1: nCChBuf = m_nCbBuffer - 1; zeroTerm(m_data, nCChBuf); m_nCbString = strlen(m_data.pszMbs); m_nCbLog = ::Latin1ToUtf8(m_data.pszMbs, m_nCbString, m_szLog, _RL_MAX_STRVAL_LENGTH); break; case VT_UTF_8: nCChBuf = m_nCbBuffer - 1; zeroTerm(m_data, nCChBuf); m_nCbString = strlen(m_data.pszMbs); m_nCbLog = _MIN(m_nCbString, _RL_MAX_STRVAL_LENGTH - 1); memcpy(m_szLog, m_data.pszMbs, m_nCbLog); m_szLog[m_nCbLog] = '\0'; break; case VT_UTF_16: nCChBuf = m_nCbBuffer / sizeof(char16_t) - 1; zeroTerm(m_data, nCChBuf); m_nCbString = wcs16len(m_data.pszWc16) * sizeof(char16_t); m_nCbLog = ::Utf16ToUtf8(m_data.pszWc16, m_nCbString / sizeof(char16_t), m_szLog, _RL_MAX_STRVAL_LENGTH); break; case VT_UTF_32: nCChBuf = m_nCbBuffer / sizeof(char32_t) - 1; zeroTerm(m_data, nCChBuf); m_nCbString = wcs32len(m_data.pszWc32) * sizeof(char32_t); m_nCbLog = ::Utf32ToUtf8(m_data.pszWc32, m_nCbString / sizeof(char32_t), m_szLog, _RL_MAX_STRVAL_LENGTH); break; case VT_Unicode: nCChBuf = m_nCbBuffer / sizeof(wchar_t) - 1; zeroTerm(m_data, nCChBuf); m_nCbString = wcslen(m_data.pszWcs) * sizeof(wchar_t); m_nCbLog = ::WcsToUtf8(m_data.pszWcs, m_nCbString / sizeof(wchar_t), m_szLog, _RL_MAX_STRVAL_LENGTH); break; default: if(fLock) Unlock(); return rv.nRetval; } memcpy(m_cache.pVoid, m_data.pVoid, m_nCbBuffer); rv.nUpdated = 1; } if(fLock) Unlock(); if(rv.nUpdated) { m_bMustLog = true; m_nUpdates++; } return rv.nRetval; } void CRemStringVariable::Log(time_t ts, CRemLogger &rlogger) { if(!m_bIsDbPersitent && m_bMustLog) { rlogger.Log(m_pszPath, m_nCbVarpath, 0.0, m_szLog, m_nCbLog, ts, false); m_bMustLog = false; } } bool CRemStringVariable::shmChanged(bool fLock) { bool bRet; if(fLock) Lock(); bRet = !!memcmp(m_cache.pVoid, m_data.pVoid, m_nCbString + 1); if(fLock) Unlock(); return bRet; } void CRemStringVariable::Lock(void) { ::GfaIpcLockSHM(m_hShm); } void CRemStringVariable::Unlock(void) { ::GfaIpcUnlockSHM(m_hShm); } void CRemStringVariable::zeroTerm(volatile V_Ptr &rp, size_t at) { switch(m_vt) { case VT_Latin1: case VT_UTF_8: rp.pszMbs[at] = '\0'; break; case VT_UTF_16: rp.pszWc16[at] = (char16_t)0; break; case VT_UTF_32: rp.pszWc32[at] = (char32_t)0; break; case VT_Unicode: rp.pszWcs[at] = L'\0'; break; default: ASSERT(false); return; } }