blob: 221672c8a2aef47b40eafc61933b1fef42953c0b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 - 2015 Profactor GmbH, ACIN, nxtControl GmbH, fortiss GmbH
* 2018 TU Wien/ACIN
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Thomas Strasser, Ingomar Müller, Rene Smodic, Alois Zoitl,
* Ingo Hegny, Martin Melik Merkumians, Stanislav Meduna
* - initial implementation and rework communication infrastructure
* Martin Melik Merkumians - fixes toString behavior for 0 size buffer
* Martin Melik Merkumians - fixes behavior for getToStringBufferSize
*******************************************************************************/
#include "forte_string.h"
#include <devlog.h>
#include "forte_uint.h"
#include "unicode_utils.h"
DEFINE_FIRMWARE_DATATYPE(STRING, g_nStringIdSTRING);
int CIEC_STRING::fromString(const char *pa_pacValue){
int nSrcLen = determineEscapedStringLength(pa_pacValue, '\'');
int nSrcCappedLength = nSrcLen;
if(0 < nSrcLen){
if((nSrcLen >= 7) && (0 == strncmp(pa_pacValue, "STRING#", 7))){
pa_pacValue += 7;
nSrcCappedLength -= 7;
}
if(static_cast<unsigned int>(nSrcLen) > scm_unMaxStringLen) {
nSrcCappedLength = scm_unMaxStringLen;
}
if (*pa_pacValue == '\'') {
reserve(static_cast<TForteUInt16>(nSrcCappedLength));
if(unescapeFromString(pa_pacValue, '\'') < 0) {
return -1;
}
} else {
assign(pa_pacValue, static_cast<TForteUInt16>(nSrcCappedLength));
}
}
return nSrcLen;
}
int CIEC_STRING::toString(char* paValue, size_t paBufferSize) const {
int nRetVal = -1;
if(0 != paValue && getToStringBufferSize() <= paBufferSize){
*paValue = '\'';
paValue++;
TForteUInt16 nLen = length();
size_t nUsedBytes = 0;
paBufferSize -= 2;
if(0 < nLen){
const char * acValue = getValue();
for(unsigned int i = 0; i < nLen; ++i){
if(nUsedBytes >= paBufferSize) {
return -1;
}
nUsedBytes += dollarEscapeChar(paValue+nUsedBytes, acValue[i], 2);
}
} else{
*paValue = '\0';
}
nRetVal = static_cast<int>(nUsedBytes);
paValue[nRetVal] = '\'';
paValue[nRetVal + 1] = '\0';
nRetVal += 2;
}
return nRetVal;
}
size_t CIEC_STRING::getToStringBufferSize() const {
const char * const stringValue = getValue();
size_t neededBufferSize = 0;
for(size_t i = 0; i < length(); ++i){
if(isprint(static_cast<unsigned char>(stringValue[i])) && '$' != stringValue[i] && '\'' != stringValue[i]){
++neededBufferSize;
}
else{
switch (stringValue[i]){
case '$':
case '\'':
case 0x10: // line feed
case '\n':
case '\f':
case '\r':
case '\t':
neededBufferSize += 2;
break;
default:
neededBufferSize += 3;
break;
}
}
}
return neededBufferSize + 2 + 1; // For Quotes and \0
}
#ifdef FORTE_UNICODE_SUPPORT
int CIEC_STRING::fromUTF8(const char *pa_pacValue, int pa_nLen, bool pa_bUnescape) {
int nSrcLen = pa_nLen >= 0 ? pa_nLen : (pa_bUnescape ? determineEscapedStringLength(pa_pacValue, '\'') : static_cast<int>(strlen(pa_pacValue)));
int nSrcCappedLength = nSrcLen;
if(0 <= nSrcLen){
if (nSrcLen == 0) {
assign("", 0);
return 0;
}
if (nSrcLen > static_cast<int>(scm_unMaxStringLen)) {
// If we get a to large string we will truncate it
// This is a conservative guess
nSrcCappedLength = scm_unMaxStringLen;
DEVLOG_WARNING("Too large string, destination will be truncated!\n");
}
unsigned int nMaxWidth;
int nLength = CUnicodeUtilities::checkUTF8(pa_pacValue, nSrcCappedLength, nMaxWidth);
if (nLength < 0) {
DEVLOG_WARNING("Invalid UTF-8 string given to fromString!\n");
*this = "***INVALID UTF-8***";
return -1;
} else if (nMaxWidth > 8) {
DEVLOG_WARNING("UTF-8 string with non-representable characters given to fromString!\n");
}
reserve(static_cast<TForteUInt16>(nLength));
if (0 == getGenData()) {
return -1;
}
TForteUInt32 nCodepoint;
const char *pRunner = pa_pacValue;
TForteByte *pEncBuffer = (TForteByte *) getValue();
TForteByte *pEncRunner = pEncBuffer;
while (*pRunner && (pRunner-pa_pacValue) < nSrcCappedLength && (pEncRunner-pEncBuffer) < nLength) {
int nRes;
nRes = CUnicodeUtilities::parseUTF8Codepoint((const TForteByte *) pRunner, nCodepoint);
pRunner += nRes;
if (nCodepoint == CUnicodeUtilities::scm_unBOMMarker) {
continue;
}
if (nCodepoint >= 0x100) {
nCodepoint = '?';
}
*pEncRunner++ = (TForteByte) nCodepoint;
}
*pEncRunner = '\0';
setLength(static_cast<TForteUInt16>(pEncRunner - pEncBuffer));
if (pa_bUnescape) {
nLength = unescapeFromString(getValue(), '\'');
if (nLength < 0) {
return -1;
}
}
}
return nSrcLen;
}
int CIEC_STRING::toUTF8(char* paBuffer, size_t paBufferSize, bool paEscape) const {
// Count the needed space
size_t nNeededLength = paEscape ? 2 : 0; // Leading and trailing delimiter
int nRes;
const unsigned char *pRunner = (const unsigned char *) getValue();
while (*pRunner) {
nRes = CUnicodeUtilities::encodeUTF8Codepoint(0, 0, (TForteUInt32) *pRunner);
if (nRes < 0) {
return -1;
}
nNeededLength += nRes;
if (nRes == 1 && paEscape && dollarEscapeChar(0, *pRunner, 0) == 2) {
nNeededLength++;
}
++pRunner;
}
if(0 == paBuffer) {
return static_cast<int>(nNeededLength);
}
if(nNeededLength + 1 > paBufferSize) {
return -1;
}
char *pEncRunner = paBuffer;
char *pDataEnd = paBuffer + nNeededLength;
if(paEscape) {
*pEncRunner++ = '\'';
}
pRunner = (const unsigned char *) getValue();
while (*pRunner) {
nRes = CUnicodeUtilities::encodeUTF8Codepoint((TForteByte *) pEncRunner, static_cast<unsigned int>(pDataEnd - pEncRunner), (TForteUInt32) *pRunner);
if(nRes == 1 && paEscape) {
nRes = dollarEscapeChar(pEncRunner, *pRunner, static_cast<unsigned int>(pDataEnd - pEncRunner));
}
if(nRes < 0) {
return -1;
}
pEncRunner += nRes;
++pRunner;
}
if(paEscape) {
*pEncRunner++ = '\'';
}
*pEncRunner = '\0';
return static_cast<int>(pEncRunner - paBuffer);
}
#endif