diff --git a/poincare/include/poincare/serialization_helper.h b/poincare/include/poincare/serialization_helper.h index e0ed71193..061e587ce 100644 --- a/poincare/include/poincare/serialization_helper.h +++ b/poincare/include/poincare/serialization_helper.h @@ -6,6 +6,12 @@ namespace Poincare { +/* The serialization methods write their argument as a string in the given + * buffer, with a null-terminating 0. The return value is: + * -> -1 if the buffer size is 0 + * -> Otherwise, the number of chars written, without the null terminating 0 + */ + namespace SerializationHelper { // SerializableReference to text int Infix( @@ -30,7 +36,6 @@ namespace SerializationHelper { // Write one char in a buffer int Char(char * buffer, int bufferSize, char c); // Write one code point in a buffer - constexpr int MaxSerializedCodePointSize = CodePoint::MaxCodePointCharLength + 1; // Null-terminating char int CodePoint(char * buffer, int bufferSize, CodePoint c); }; diff --git a/poincare/src/constant.cpp b/poincare/src/constant.cpp index 788cf5135..329babeda 100644 --- a/poincare/src/constant.cpp +++ b/poincare/src/constant.cpp @@ -93,7 +93,7 @@ bool ConstantNode::isConstantCodePoint(CodePoint c) const { } Constant Constant::Builder(CodePoint c) { - constexpr int bufferSize = SerializationHelper::MaxSerializedCodePointSize; + constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; char buffer[bufferSize]; size_t codePointSize = SerializationHelper::CodePoint(buffer, bufferSize, c); return SymbolAbstract::Builder(buffer, codePointSize); diff --git a/poincare/src/serialization_helper.cpp b/poincare/src/serialization_helper.cpp index 71cb9dc39..f77ddd247 100644 --- a/poincare/src/serialization_helper.cpp +++ b/poincare/src/serialization_helper.cpp @@ -5,24 +5,57 @@ namespace Poincare { -static void serializeChild(const TreeNode * childNode, const TreeNode * parentNode, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfDigits, int * numberOfChar) { +static inline int min(int x, int y) { return x < y ? x : y; } + +static bool checkBufferSize(char * buffer, int bufferSize, int * result) { + // If buffer has size 0 or 1, put a zero if it fits and return + if (bufferSize == 0) { + *result = -1; + return true; + } + + buffer[bufferSize-1] = 0; // Null-terminate the buffer + if (bufferSize == 1) { + *result = 0; + return true; + } + return false; +} + +static int serializeChild( + const TreeNode * childNode, + const TreeNode * parentNode, + char * buffer, + int bufferSize, + Preferences::PrintFloatMode floatDisplayMode, + int numberOfDigits) +{ + { + int result = 0; + if (checkBufferSize(buffer, bufferSize, &result)) { + return result; + } + } + + int numberOfChar = 0; // Write the child with parentheses if needed bool addParentheses = parentNode->childNeedsParenthesis(childNode); if (addParentheses) { - buffer[*numberOfChar] = '('; - *numberOfChar = *numberOfChar + 1; - if (*numberOfChar >= bufferSize-1) { - return; + buffer[numberOfChar++] = '('; + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; } } - *numberOfChar += childNode->serialize(buffer + *numberOfChar, bufferSize - *numberOfChar, floatDisplayMode, numberOfDigits); - if (*numberOfChar >= bufferSize-1) { - return; + numberOfChar+= childNode->serialize(buffer + numberOfChar, bufferSize - numberOfChar, floatDisplayMode, numberOfDigits); + if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); + return bufferSize-1; } if (addParentheses) { - buffer[*numberOfChar] = ')'; - *numberOfChar = *numberOfChar + 1; + buffer[numberOfChar++] = ')'; } + buffer[numberOfChar] = 0; + return numberOfChar; } int SerializationHelper::Infix( @@ -35,14 +68,11 @@ int SerializationHelper::Infix( int firstChildIndex, int lastChildIndex) { - // If buffer has size 0 or 1, put a zero if it fits and return - if (bufferSize == 0) { - return -1; - } - - buffer[bufferSize-1] = 0; // Null-terminate the buffer - if (bufferSize == 1) { - return 0; + { + int result = 0; + if (checkBufferSize(buffer, bufferSize, &result)) { + return result; + } } // Get some information on the node @@ -51,8 +81,9 @@ int SerializationHelper::Infix( assert(numberOfChildren > 0); // Write the first child, with parentheses if needed - serializeChild(node->childAtIndex(firstChildIndex), node, buffer, bufferSize, floatDisplayMode, numberOfDigits, &numberOfChar); + numberOfChar+= serializeChild(node->childAtIndex(firstChildIndex), node, buffer + numberOfChar, bufferSize - numberOfChar, floatDisplayMode, numberOfDigits); if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); return bufferSize-1; } // For all remaining children: @@ -61,11 +92,13 @@ int SerializationHelper::Infix( // Write the operator numberOfChar += strlcpy(buffer+numberOfChar, operatorName, bufferSize-numberOfChar); if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); return bufferSize-1; } // Write the child, with parentheses if needed - serializeChild(node->childAtIndex(i), node, buffer, bufferSize, floatDisplayMode, numberOfDigits, &numberOfChar); + numberOfChar+= serializeChild(node->childAtIndex(i), node, buffer + numberOfChar, bufferSize - numberOfChar, floatDisplayMode, numberOfDigits); if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); return bufferSize-1; } } @@ -84,18 +117,17 @@ int SerializationHelper::Prefix( const char * operatorName, bool writeFirstChild) { - // If buffer has size 0 or 1, put a zero if it fits and return - if (bufferSize == 0) { - return -1; - } - buffer[bufferSize-1] = 0; - if (bufferSize == 1) { - return 0; + { + int result = 0; + if (checkBufferSize(buffer, bufferSize, &result)) { + return result; + } } // Copy the operator name int numberOfChar = strlcpy(buffer, operatorName, bufferSize); if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); return bufferSize-1; } @@ -115,6 +147,7 @@ int SerializationHelper::Prefix( // Write the first child numberOfChar += node->childAtIndex(firstChildIndex)->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits); if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); return bufferSize-1; } @@ -126,6 +159,7 @@ int SerializationHelper::Prefix( } numberOfChar += node->childAtIndex(i)->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits); if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); return bufferSize-1; } } @@ -138,12 +172,11 @@ int SerializationHelper::Prefix( } int SerializationHelper::Char(char * buffer, int bufferSize, char c) { - if (bufferSize == 0) { - return -1; - } - if (bufferSize == 1) { - buffer[0] = 0; - return 0; + { + int result = 0; + if (checkBufferSize(buffer, bufferSize, &result)) { + return result; + } } buffer[0] = c; buffer[1] = 0; @@ -151,12 +184,11 @@ int SerializationHelper::Char(char * buffer, int bufferSize, char c) { } int SerializationHelper::CodePoint(char * buffer, int bufferSize, class CodePoint c) { - if (bufferSize == 0) { - return -1; - } - if (bufferSize == 1) { - buffer[0] = 0; - return 0; + { + int result = 0; + if (checkBufferSize(buffer, bufferSize, &result)) { + return result; + } } size_t size = UTF8Decoder::CodePointToChars(c, buffer, bufferSize); int nullTerminatingIndex = min(size, bufferSize - 1);