Files
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

768 lines
19 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "MemoryUtils.h"
#include "StringExt.h"
#include "Utils.h"
namespace NSFontConverter
{
//------------------------------------------------------------------------
union StringExtFormatArg
{
int iValue;
unsigned int uiValue;
long lValue;
unsigned long ulValue;
double fValue;
char cValue;
char *sValue;
StringExt *seValue;
};
enum StringExtFormatType
{
fmtIntDecimal,
fmtIntHex,
fmtIntOctal,
fmtIntBinary,
fmtUIntDecimal,
fmtUIntHex,
fmtUIntOctal,
fmtUIntBinary,
fmtLongDecimal,
fmtLongHex,
fmtLongOctal,
fmtLongBinary,
fmtULongDecimal,
fmtULongHex,
fmtULongOctal,
fmtULongBinary,
fmtDouble,
fmtDoubleTrim,
fmtChar,
fmtString,
fmtStringExt,
fmtSpace
};
static char *c_arrsFormatStrings[] =
{
"d", "x", "o", "b", "ud", "ux", "uo", "ub",
"ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
"f", "g",
"c",
"s",
"t",
"w",
NULL
};
//------------------------------------------------------------------------
static inline int Size(int nLen)
{
int nDelta;
for ( nDelta = 8; nDelta < nLen && nDelta < 0x100000; nDelta <<= 1 ) ;
// ((nLen + 1) + (delta - 1)) & ~(delta - 1)
return (nLen + nDelta) & ~( nDelta - 1);
}
inline void StringExt::Resize(int nLength)
{
char *sTemp = NULL;
if ( !m_sData )
m_sData = new char[Size(nLength)];
else if ( Size(nLength) != Size(m_nLength) )
{
sTemp = new char[ Size(nLength) ];
if ( nLength < m_nLength )
{
memcpy( sTemp, m_sData, nLength);
sTemp[nLength] = '\0';
}
else
memcpy( sTemp, m_sData, m_nLength + 1);
delete[] m_sData;
m_sData = sTemp;
}
}
StringExt::StringExt()
{
m_sData = NULL;
Resize( m_nLength = 0 );
m_sData[0] = '\0';
}
StringExt::StringExt(const char *sSrc)
{
int nLen = (int)strlen( sSrc );
m_sData = NULL;
Resize(m_nLength = nLen);
memcpy(m_sData, sSrc, nLen + 1);
}
StringExt::StringExt(const char *sSrc, int nLength)
{
m_sData = NULL;
Resize( m_nLength = nLength );
memcpy( m_sData, sSrc, m_nLength * sizeof(char) );
m_sData[m_nLength] = '\0';
}
StringExt::StringExt(StringExt *seSrc, int nIndex, int nLength)
{
m_sData = NULL;
Resize( m_nLength = nLength );
memcpy( m_sData, seSrc->GetBuffer() + nIndex, m_nLength);
m_sData[ m_nLength ] = '\0';
}
StringExt::StringExt(StringExt *seSrc)
{
m_sData = NULL;
Resize( m_nLength = seSrc->GetLength() );
memcpy( m_sData, seSrc->GetBuffer(), m_nLength + 1);
}
StringExt::StringExt(StringExt *seString1, StringExt *seString2)
{
int nLen1 = seString1->GetLength();
int nLen2 = seString2->GetLength();
m_sData = NULL;
Resize( m_nLength = nLen1 + nLen2 );
memcpy( m_sData, seString1->GetBuffer(), nLen1 );
memcpy( m_sData + nLen1, seString2->GetBuffer(), nLen2 + 1 );
}
StringExt *StringExt::FromInt(int nValue)
{
char sBuffer[24];
char *pData = NULL;
int nLen;
FormatInt( nValue, sBuffer, sizeof( sBuffer ), false, 0, 10, &pData, &nLen);
return new StringExt( pData, nLen );
}
StringExt *StringExt::Format(char *sFormat, ...)
{
va_list sArgList;
StringExt *seResult = new StringExt();
va_start( sArgList, sFormat );
seResult->AppendFormatV( sFormat, sArgList);
va_end( sArgList );
return seResult;
}
StringExt *StringExt::FormatV(char *sFormat, va_list sArgList)
{
StringExt *seResult = new StringExt();
seResult->AppendFormatV( sFormat, sArgList );
return seResult;
}
StringExt::~StringExt()
{
delete[] m_sData;
}
StringExt *StringExt::Clear()
{
m_sData[ m_nLength = 0 ] = '\0';
Resize(0);
return this;
}
StringExt *StringExt::Append(char nChar)
{
Resize( m_nLength + 1 );
m_sData[ m_nLength++ ] = nChar;
m_sData[ m_nLength ] = '\0';
return this;
}
StringExt *StringExt::Append(StringExt *seString)
{
int nLen = seString->GetLength();
Resize( m_nLength + nLen );
memcpy( m_sData + m_nLength, seString->GetBuffer(), nLen + 1 );
m_nLength += nLen;
return this;
}
StringExt *StringExt::Append(const char *sString)
{
int nLen = strlen( sString );
Resize( m_nLength + nLen );
memcpy( m_sData + m_nLength, sString, nLen + 1 );
m_nLength += nLen;
return this;
}
StringExt *StringExt::Append(const char *sString, int nLength)
{
Resize( m_nLength + nLength );
memcpy( m_sData + m_nLength, sString, nLength );
m_nLength += nLength;
m_sData[ m_nLength ] = '\0';
return this;
}
StringExt *StringExt::AppendFormat(char *sFormat, ...)
{
va_list sArgList;
va_start( sArgList, sFormat );
AppendFormatV( sFormat, sArgList );
va_end( sArgList );
return this;
}
StringExt *StringExt::AppendFormatV(char *sFormat, va_list sArgList)
{
StringExtFormatArg uArg;
int nIndex, nWidth, nPrecision;
bool bReverseAlign, bZeroFill;
StringExtFormatType eFormatType;
char sBuffer[65];
int nLen;
char *pCur, *pTemp, *sTemp;
int nArgsLen = 0;
int nArgsSize = 8;
StringExtFormatArg *arrArgs = (StringExtFormatArg *)MemUtilsMallocArray( nArgsSize, sizeof(StringExtFormatArg));
pCur = sFormat;
while ( *pCur )
{
if ( *pCur == '{' )
{
++pCur;
if ( *pCur == '{' )
{
++pCur;
Append('{');
}
else
{
// Разбираем форматированную строку
if ( !(*pCur >= '0' && *pCur <= '9') )
break;
nIndex = *pCur - '0';
for (++pCur; *pCur >= '0' && *pCur <= '9'; ++pCur )
nIndex = 10 * nIndex + (*pCur - '0');
if ( *pCur != ':' )
break;
++pCur;
if ( *pCur == '-' )
{
bReverseAlign = true;
++pCur;
}
else
bReverseAlign = false;
nWidth = 0;
bZeroFill = *pCur == '0';
for (; *pCur >= '0' && *pCur <= '9'; ++pCur )
nWidth = 10 * nWidth + (*pCur - '0');
if ( *pCur == '.' )
{
++pCur;
nPrecision = 0;
for (; *pCur >= '0' && *pCur <= '9'; ++pCur )
{
nPrecision = 10 * nPrecision + (*pCur - '0');
}
}
else
{
nPrecision = 0;
}
for ( eFormatType = (StringExtFormatType)0;
c_arrsFormatStrings[ eFormatType ];
eFormatType = (StringExtFormatType)( eFormatType + 1 ) )
{
if (!strncmp( pCur, c_arrsFormatStrings[ eFormatType ], strlen(c_arrsFormatStrings[ eFormatType ])))
{
break;
}
}
if ( !c_arrsFormatStrings[ eFormatType ] )
{
break;
}
pCur += strlen( c_arrsFormatStrings[ eFormatType ] );
if (*pCur != '}')
{
break;
}
++pCur;
// fetch the argument
if ( nIndex > nArgsLen )
{
break;
}
if ( nIndex == nArgsLen )
{
if ( nArgsLen == nArgsSize )
{
nArgsSize *= 2;
arrArgs = (StringExtFormatArg *)MemUtilsReallocArray( arrArgs, nArgsSize, sizeof(StringExtFormatArg));
}
switch ( eFormatType )
{
case fmtIntDecimal:
case fmtIntHex:
case fmtIntOctal:
case fmtIntBinary:
case fmtSpace:
arrArgs[nArgsLen].iValue = va_arg( sArgList, int );
break;
case fmtUIntDecimal:
case fmtUIntHex:
case fmtUIntOctal:
case fmtUIntBinary:
arrArgs[nArgsLen].uiValue = va_arg( sArgList, unsigned int );
break;
case fmtLongDecimal:
case fmtLongHex:
case fmtLongOctal:
case fmtLongBinary:
arrArgs[nArgsLen].lValue = va_arg( sArgList, long );
break;
case fmtULongDecimal:
case fmtULongHex:
case fmtULongOctal:
case fmtULongBinary:
arrArgs[nArgsLen].ulValue = va_arg( sArgList, unsigned long );
break;
case fmtDouble:
case fmtDoubleTrim:
arrArgs[nArgsLen].fValue = va_arg( sArgList, double );
break;
case fmtChar:
arrArgs[nArgsLen].cValue = (char)va_arg( sArgList, int );
break;
case fmtString:
arrArgs[nArgsLen].sValue = va_arg( sArgList, char * );
break;
case fmtStringExt:
arrArgs[nArgsLen].seValue = va_arg(sArgList, StringExt *);
break;
}
++nArgsLen;
}
uArg = arrArgs[ nIndex ];
switch ( eFormatType )
{
case fmtIntDecimal:
FormatInt( uArg.iValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 10, &sTemp, &nLen );
break;
case fmtIntHex:
FormatInt( uArg.iValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 16, &sTemp, &nLen );
break;
case fmtIntOctal:
FormatInt( uArg.iValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 8, &sTemp, &nLen );
break;
case fmtIntBinary:
FormatInt( uArg.iValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 2, &sTemp, &nLen );
break;
case fmtUIntDecimal:
FormatUInt( uArg.uiValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 10, &sTemp, &nLen );
break;
case fmtUIntHex:
FormatUInt( uArg.uiValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 16, &sTemp, &nLen );
break;
case fmtUIntOctal:
FormatUInt( uArg.uiValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 8, &sTemp, &nLen );
break;
case fmtUIntBinary:
FormatUInt( uArg.uiValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 2, &sTemp, &nLen );
break;
case fmtLongDecimal:
FormatInt( uArg.lValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 10, &sTemp, &nLen );
break;
case fmtLongHex:
FormatInt( uArg.lValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 16, &sTemp, &nLen );
break;
case fmtLongOctal:
FormatInt( uArg.lValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 8, &sTemp, &nLen );
break;
case fmtLongBinary:
FormatInt( uArg.lValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 2, &sTemp, &nLen );
break;
case fmtULongDecimal:
FormatUInt( uArg.ulValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 10, &sTemp, &nLen );
break;
case fmtULongHex:
FormatUInt( uArg.ulValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 16, &sTemp, &nLen );
break;
case fmtULongOctal:
FormatUInt( uArg.ulValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 8, &sTemp, &nLen );
break;
case fmtULongBinary:
FormatUInt( uArg.ulValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 2, &sTemp, &nLen );
break;
case fmtDouble:
FormatDouble( uArg.fValue, sBuffer, sizeof(sBuffer), nPrecision, false, &sTemp, &nLen );
break;
case fmtDoubleTrim:
FormatDouble( uArg.fValue, sBuffer, sizeof(sBuffer), nPrecision, true, &sTemp, &nLen );
break;
case fmtChar:
sBuffer[0] = uArg.cValue;
sTemp = sBuffer;
nLen = 1;
bReverseAlign = !bReverseAlign;
break;
case fmtString:
sTemp = uArg.sValue;
nLen = strlen( sTemp );
bReverseAlign = !bReverseAlign;
break;
case fmtStringExt:
sTemp = uArg.seValue->GetBuffer();
nLen = uArg.seValue->GetLength();
bReverseAlign = !bReverseAlign;
break;
case fmtSpace:
sTemp = sBuffer;
nLen = 0;
nWidth = uArg.iValue;
break;
}
// Добавляем аргумент в нужном формате, с нужным прилеганием
if ( !bReverseAlign && nLen < nWidth )
{
for (int nCounter = nLen; nCounter < nWidth; ++nCounter )
Append(' ');
}
Append( sTemp, nLen);
if ( bReverseAlign && nLen < nWidth )
{
for (int nCounter = nLen; nCounter < nWidth; ++nCounter )
Append(' ');
}
}
}
else if ( *pCur == '}' )
{
++pCur;
if ( *pCur == '}' )
++pCur;
Append('}');
}
else
{
for ( pTemp = pCur + 1; *pTemp && *pTemp != '{' && *pTemp != '}'; ++pTemp ) ;
Append( pCur, pTemp - pCur );
pCur = pTemp;
}
}
MemUtilsFree( arrArgs );
return this;
}
void StringExt::FormatInt ( long nValue, char *sBuffer, int nBufferSize, bool bZeroFill, int nWidth, int nBase, char **ppData, int *pnLen)
{
static char c_sValues[17] = "0123456789abcdef";
bool bNegative = false;
int nStart;
int nCur = nBufferSize;
if ( ( bNegative = nValue < 0 ) )
{
nValue = -nValue;
}
nStart = bNegative ? 1 : 0;
if ( nValue == 0 )
{
sBuffer[--nCur] = '0';
}
else
{
while ( nCur > nStart && nValue )
{
sBuffer[--nCur] = c_sValues[ nValue % nBase ];
nValue /= nBase;
}
}
if ( bZeroFill )
{
for (int nCounter = nBufferSize - nCur; nCur > nStart && nCounter < nWidth - nStart; ++nCounter )
{
sBuffer[--nCur] = '0';
}
}
if ( bNegative )
{
sBuffer[--nCur] = '-';
}
*ppData = sBuffer + nCur;
*pnLen = nBufferSize - nCur;
}
void StringExt::FormatUInt(unsigned long nValue, char *sBuffer, int nBufferSize, bool bZeroFill, int nWidth, int nBase, char **ppData, int *pnLen)
{
static char c_sValues[17] = "0123456789abcdef";
int nCur = nBufferSize;
if (nValue == 0)
{
sBuffer[--nCur] = '0';
}
else
{
while (nCur > 0 && nValue)
{
sBuffer[--nCur] = c_sValues[nValue % nBase];
nValue /= nBase;
}
}
if (bZeroFill)
{
for (int nCounter = nBufferSize - nCur; nCur > 0 && nCounter < nWidth; ++nCounter )
{
sBuffer[--nCur] = '0';
}
}
*ppData = sBuffer + nCur;
*pnLen = nBufferSize - nCur;
}
void StringExt::FormatDouble( double dValue, char *sBuffer, int nBufferSize, int nPrecision, bool bTrim, char **ppData, int *pnLen)
{
bool bNegative = false, bStarted = false;
double dTemp = 0;
int nInt;
if ( bNegative = ( dValue < 0 ) )
dValue = -dValue;
dValue = floor( dValue * pow( (double)10, nPrecision) + 0.5);
int nCur = nBufferSize;
bStarted = !bTrim;
for (int nCounter = 0; nCounter < nPrecision && nCur > 1; ++nCounter )
{
dTemp = floor(0.1 * (dValue + 0.5));
nInt = (int)floor( dValue - 10 * dTemp + 0.5);
if ( bStarted || nInt != 0 )
{
sBuffer[--nCur] = '0' + nInt;
bStarted = true;
}
dValue = dTemp;
}
if ( nCur > 1 && bStarted )
sBuffer[--nCur] = '.';
if ( nCur > 1 )
{
do {
dTemp = floor( 0.1 * ( dValue + 0.5 ) );
nInt = (int)floor(dValue - 10 * dTemp + 0.5);
sBuffer[--nCur] = '0' + nInt;
dValue = dTemp;
} while ( nCur > 1 && dValue );
}
if (bNegative)
sBuffer[--nCur] = '-';
*ppData = sBuffer + nCur;
*pnLen = nBufferSize - nCur;
}
StringExt *StringExt::Insert(int nIndex, char nChar)
{
Resize( m_nLength + 1 );
for (int nJ = m_nLength + 1; nJ > nIndex; --nJ )
m_sData[ nJ ] = m_sData[ nJ - 1 ];
m_sData[ nIndex ] = nChar;
++m_nLength;
return this;
}
StringExt *StringExt::Insert(int nIndex, StringExt *seString)
{
int nLen = seString->GetLength();
Resize( m_nLength + nLen );
for (int nJ = m_nLength; nJ >= nIndex; --nJ )
m_sData[ nJ + nLen ] = m_sData[ nJ ];
memcpy( m_sData + nIndex, seString->GetBuffer(), nLen );
m_nLength += nLen;
return this;
}
StringExt *StringExt::Insert(int nIndex, const char *sString)
{
int nLen = strlen( sString );
Resize(m_nLength + nLen);
for (int nJ = m_nLength; nJ >= nIndex; --nJ )
m_sData[ nJ + nLen ] = m_sData[ nJ ];
memcpy( m_sData + nIndex, sString, nLen);
m_nLength += nLen;
return this;
}
StringExt *StringExt::Insert(int nIndex, const char *sString, int nLength)
{
Resize( m_nLength + nLength );
for (int nJ = m_nLength; nJ >= nIndex; --nJ )
m_sData[ nJ + nLength ] = m_sData[ nJ ];
memcpy( m_sData + nIndex, sString, nLength );
m_nLength += nLength;
return this;
}
StringExt *StringExt::Delete(int nIndex, int nCount)
{
if ( nCount > 0 )
{
if ( nIndex + nCount > m_nLength)
nCount = m_nLength - nIndex;
for (int nJ = nIndex; nJ <= m_nLength - nCount; ++nJ )
{
m_sData[ nJ ] = m_sData[ nJ + nCount ];
}
Resize( m_nLength -= nCount );
}
return this;
}
StringExt *StringExt::MakeUpper()
{
for ( int nIndex = 0; nIndex < m_nLength; ++nIndex )
{
if ( islower( m_sData[ nIndex ] ) )
m_sData[nIndex] = toupper( m_sData[nIndex] );
}
return this;
}
StringExt *StringExt::MakeLower()
{
for (int nIndex = 0; nIndex < m_nLength; ++nIndex)
{
if (isupper(m_sData[nIndex]))
m_sData[nIndex] = tolower(m_sData[nIndex]);
}
return this;
}
int StringExt::Compare (StringExt *seOther)
{
int nIndex = 0;
char *pThis, *pOther;
int nThisLen = m_nLength;
int nOtherLen = seOther->m_nLength;
for (nIndex = 0, pThis = m_sData, pOther = seOther->m_sData; nIndex < nThisLen && nIndex < nOtherLen; ++nIndex, ++pThis, ++pOther)
{
int nRes = *pThis - *pOther;
if ( 0 != nRes )
return nRes;
}
return nThisLen - nOtherLen;
}
int StringExt::CompareN(StringExt *seOther, int nCount)
{
int nIndex;
char *pThis, *pOther;
int nThisLen = m_nLength;
int nOtherLen = seOther->m_nLength;
for (nIndex = 0, pThis = m_sData, pOther = seOther->m_sData; nIndex < nThisLen && nIndex < nOtherLen && nIndex < nCount; ++nIndex, ++pThis, ++pOther)
{
int nRes = *pThis - *pOther;
if ( 0 != nRes )
return nRes;
}
if (nIndex == nCount)
return 0;
return nThisLen - nOtherLen;
}
int StringExt::Compare (const char *sOther)
{
int nIndex;
const char *pThis, *pOther;
int nThisLen = m_nLength;
for (nIndex = 0, pThis = m_sData, pOther = sOther; nIndex < nThisLen && *pOther; ++nIndex, ++pThis, ++pOther)
{
int nRes = *pThis - *pOther;
if ( 0 != nRes )
return nRes;
}
if ( nIndex < nThisLen )
return 1;
if ( *pOther )
return -1;
return 0;
}
int StringExt::CompareN(const char *sOther, int nCount)
{
int nIndex;
const char *pThis, *pOther;
int nThisLen = m_nLength;
for (nIndex = 0, pThis = m_sData, pOther = sOther; nIndex < nThisLen && *pOther && nIndex < nCount; ++nIndex, ++pThis, ++pOther )
{
int nRes = *pThis - *pOther;
if ( 0 != nRes )
return nRes;
}
if ( nIndex == nCount )
return 0;
if ( nIndex < nThisLen)
return 1;
if ( *pOther )
return -1;
return 0;
}
}