SolidSyslog coverage report
Current view: top level - Core/Source - SolidSyslogFormatter.c (source / functions) Coverage Total Hit
Test: SolidSyslog Lines: 100.0 % 208 208
Test Date: 2026-11-12 23:14:35 Functions: 100.0 % 42 42
Branches: 99.4 % 158 157

             Branch data     Line data    Source code
       1                 :             : /* SPDX-FileCopyrightText: Copyright 2026 Cozens Software Solutions Limited
       2                 :             :  * SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0 OR LicenseRef-COSOSO-Commercial
       3                 :             :  */
       4                 :             : 
       5                 :             : #include "SolidSyslogFormatter.h"
       6                 :             : #include "SolidSyslogMacros.h"
       7                 :             : #include "SolidSyslogUtf8.h"
       8                 :             : 
       9                 :             : #include <stdbool.h>
      10                 :             : #include <stddef.h>
      11                 :             : 
      12                 :             : struct SolidSyslogFormatter
      13                 :             : {
      14                 :             :     size_t Size;
      15                 :             :     size_t Position;
      16                 :             :     char Buffer[];
      17                 :             : };
      18                 :             : 
      19                 :             : SOLIDSYSLOG_STATIC_ASSERT(
      20                 :             :     sizeof(struct SolidSyslogFormatter) == (SOLIDSYSLOG_FORMATTER_OVERHEAD * sizeof(SolidSyslogFormatterStorage)),
      21                 :             :     "SOLIDSYSLOG_FORMATTER_OVERHEAD does not match struct layout"
      22                 :             : );
      23                 :             : 
      24                 :             : static const char NON_PRINTABLE_SUBSTITUTE = '?';
      25                 :             : 
      26                 :             : /* UTF-8 replacement character U+FFFD, emitted in place of each invalid
      27                 :             :  * byte per Unicode section 3.9 best practice for per-byte maximal subpart. */
      28                 :             : static const char REPLACEMENT_CHARACTER[] = {'\xEF', '\xBF', '\xBD'};
      29                 :             : 
      30                 :             : /* Mutable state threaded through the EscapedString writer helpers.
      31                 :             :  * sourcePos walks the source until NUL; decodedLength counts bytes the
      32                 :             :  * reader's decoder would extract; exhausted flips when a writer can't
      33                 :             :  * fit and the loop must terminate. */
      34                 :             : struct EscapedContext
      35                 :             : {
      36                 :             :     struct SolidSyslogFormatter* Formatter;
      37                 :             :     const char* Source;
      38                 :             :     size_t SourcePos;
      39                 :             :     size_t DecodedLength;
      40                 :             :     size_t MaxDecodedLength;
      41                 :             :     bool Exhausted;
      42                 :             : };
      43                 :             : 
      44                 :             : static inline bool Formatter_CodepointFits(size_t codepointLength, size_t remainingDecodedLength);
      45                 :             : static inline bool Formatter_Fits(const struct EscapedContext* context, size_t decodedAdvance);
      46                 :             : static inline bool Formatter_HasCapacity(const struct SolidSyslogFormatter* formatter);
      47                 :             : static inline bool Formatter_IsAboveUnicodeMaxEncoding(char lead, char continuation1);
      48                 :             : static inline bool Formatter_IsOverlongFourByteEncoding(char lead, char continuation1);
      49                 :             : static inline bool Formatter_IsOverlongThreeByteEncoding(char lead, char continuation1);
      50                 :             : static inline bool Formatter_IsOverlongTwoByteLead(char byte);
      51                 :             : static inline bool Formatter_IsAsciiCharacter(char value);
      52                 :             : static inline bool Formatter_IsExhausted(const struct EscapedContext* context);
      53                 :             : static inline bool Formatter_IsPrintableUsAscii(char value);
      54                 :             : static inline bool Formatter_IsUtf16SurrogateEncoding(char lead, char continuation1);
      55                 :             : static inline bool Formatter_IsValidUtf8FourByte(char lead, char continuation1, char continuation2, char continuation3);
      56                 :             : static inline bool Formatter_IsValidUtf8ThreeByte(char lead, char continuation1, char continuation2);
      57                 :             : static inline bool Formatter_IsValidUtf8TwoByte(char lead, char continuation1);
      58                 :             : static inline bool Formatter_NeedsEscape(char value);
      59                 :             : static inline char Formatter_DigitToChar(uint32_t value);
      60                 :             : static size_t Formatter_CountDigits(uint32_t value);
      61                 :             : static inline size_t Formatter_Utf8CodepointLength(const char* source);
      62                 :             : static inline void Formatter_Exhaust(struct EscapedContext* context);
      63                 :             : static inline void Formatter_NullTerminate(struct SolidSyslogFormatter* formatter);
      64                 :             : static inline void Formatter_TrimTruncatedMultiByteTail(struct SolidSyslogFormatter* formatter);
      65                 :             : static inline void Formatter_WriteBytes(struct SolidSyslogFormatter* formatter, const char* bytes, size_t count);
      66                 :             : static inline void Formatter_WriteChar(struct SolidSyslogFormatter* formatter, char value);
      67                 :             : static inline void Formatter_WriteCodepoint(struct EscapedContext* context);
      68                 :             : /* NOLINTBEGIN(bugprone-easily-swappable-parameters) -- 3 callers in this file pass compile-time constants or codepointLength; param names disambiguate */
      69                 :             : static inline void Formatter_WriteContext(
      70                 :             :     struct EscapedContext* context,
      71                 :             :     const char* bytes,
      72                 :             :     size_t byteCount,
      73                 :             :     size_t sourceAdvance,
      74                 :             :     size_t decodedAdvance
      75                 :             : );
      76                 :             : /* NOLINTEND(bugprone-easily-swappable-parameters) */
      77                 :             : static inline void Formatter_WriteEscaped(struct EscapedContext* context);
      78                 :             : static inline void Formatter_WritePrintableUsAsciiChar(struct SolidSyslogFormatter* formatter, char value);
      79                 :             : static inline void Formatter_WriteReplacement(struct EscapedContext* context);
      80                 :             : 
      81                 :       46441 : struct SolidSyslogFormatter* SolidSyslogFormatter_Create(SolidSyslogFormatterStorage* storage, size_t bufferSize)
      82                 :             : {
      83                 :       46441 :     struct SolidSyslogFormatter* formatter = (struct SolidSyslogFormatter*) storage;
      84                 :       46441 :     formatter->Size = bufferSize;
      85                 :       46441 :     formatter->Position = 0;
      86                 :       46441 :     Formatter_NullTerminate(formatter);
      87                 :       46441 :     return formatter;
      88                 :             : }
      89                 :             : 
      90                 :      349746 : static inline void Formatter_NullTerminate(struct SolidSyslogFormatter* formatter)
      91                 :             : {
      92         [ +  + ]:      349746 :     if (formatter->Size > 0U)
      93                 :             :     {
      94                 :      343025 :         formatter->Buffer[formatter->Position] = '\0';
      95                 :             :     }
      96                 :      349746 : }
      97                 :             : 
      98                 :      144253 : void SolidSyslogFormatter_AsciiCharacter(struct SolidSyslogFormatter* formatter, char value)
      99                 :             : {
     100                 :      144253 :     char emitted = value;
     101         [ +  + ]:      144253 :     if (!Formatter_IsAsciiCharacter(emitted))
     102                 :             :     {
     103                 :           3 :         emitted = NON_PRINTABLE_SUBSTITUTE;
     104                 :             :     }
     105                 :      144253 :     Formatter_WriteChar(formatter, emitted);
     106                 :      144253 :     Formatter_NullTerminate(formatter);
     107                 :      144253 : }
     108                 :             : 
     109                 :        6558 : void SolidSyslogFormatter_Bom(struct SolidSyslogFormatter* formatter)
     110                 :             : {
     111                 :             :     /* UTF-8 byte order mark U+FEFF, required at the start of a UTF-8 MSG
     112                 :             :      * by RFC 5424 section 6.4. */
     113                 :             :     static const char UTF8_BOM[] = {'\xEF', '\xBB', '\xBF'};
     114                 :        6558 :     Formatter_WriteBytes(formatter, UTF8_BOM, sizeof(UTF8_BOM));
     115                 :        6558 :     Formatter_NullTerminate(formatter);
     116                 :        6558 : }
     117                 :             : 
     118                 :       26660 : void SolidSyslogFormatter_NilValue(struct SolidSyslogFormatter* formatter)
     119                 :             : {
     120                 :             :     /* RFC 5424 section 6 NILVALUE - a single '-' standing in for an absent field. */
     121                 :       26660 :     SolidSyslogFormatter_AsciiCharacter(formatter, '-');
     122                 :       26660 : }
     123                 :             : 
     124                 :      144253 : static inline bool Formatter_IsAsciiCharacter(char value)
     125                 :             : {
     126   [ +  +  +  + ]:      144253 :     return (value == ' ') || Formatter_IsPrintableUsAscii(value);
     127                 :             : }
     128                 :             : 
     129                 :      974867 : static inline void Formatter_WriteChar(struct SolidSyslogFormatter* formatter, char value)
     130                 :             : {
     131         [ +  + ]:      974867 :     if (Formatter_HasCapacity(formatter))
     132                 :             :     {
     133                 :      974558 :         formatter->Buffer[formatter->Position] = value;
     134                 :      974558 :         formatter->Position++;
     135                 :             :     }
     136                 :      974867 : }
     137                 :             : 
     138                 :      974867 : static inline bool Formatter_HasCapacity(const struct SolidSyslogFormatter* formatter)
     139                 :             : {
     140   [ +  +  +  + ]:      974867 :     return (formatter->Size > 0U) && (formatter->Position < (formatter->Size - 1U));
     141                 :             : }
     142                 :             : 
     143                 :             : /*
     144                 :             :  * UTF-8 validation per RFC 3629 section 4 and Unicode section 3.9.
     145                 :             :  *
     146                 :             :  *   1-byte  0xxxxxxx                                   U+0000  - U+007F
     147                 :             :  *   2-byte  110xxxxx 10xxxxxx                          U+0080  - U+07FF    lead C2-DF
     148                 :             :  *   3-byte  1110xxxx 10xxxxxx 10xxxxxx                 U+0800  - U+FFFF    lead E0-EF
     149                 :             :  *   4-byte  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx        U+10000 - U+10FFFF  lead F0-F4
     150                 :             :  *
     151                 :             :  * Excluded sequences:
     152                 :             :  *   C0, C1             overlong 2-byte encodings
     153                 :             :  *   E0 + cont1 80-9F   overlong 3-byte encodings
     154                 :             :  *   ED + cont1 A0-BF   UTF-16 surrogate range (U+D800..U+DFFF)
     155                 :             :  *   F0 + cont1 80-8F   overlong 4-byte encodings
     156                 :             :  *   F4 + cont1 90-BF   codepoints above U+10FFFF
     157                 :             :  *   F5-F7              codepoints above U+10FFFF
     158                 :             :  *   F8-FF              5+ byte prefix patterns removed by RFC 3629
     159                 :             :  */
     160                 :             : 
     161                 :       63315 : void SolidSyslogFormatter_BoundedString(struct SolidSyslogFormatter* formatter, const char* source, size_t maxLength)
     162                 :             : {
     163                 :       63315 :     size_t len = 0U;
     164                 :             : 
     165   [ +  +  +  + ]:      616357 :     while ((len < maxLength) && (source[len] != '\0'))
     166                 :             :     {
     167                 :      553042 :         size_t codepointLength = Formatter_Utf8CodepointLength(&source[len]);
     168                 :             : 
     169         [ +  + ]:      553042 :         if (Formatter_CodepointFits(codepointLength, maxLength - len))
     170                 :             :         {
     171                 :      552982 :             Formatter_WriteBytes(formatter, &source[len], codepointLength);
     172                 :      552982 :             len += codepointLength;
     173                 :             :         }
     174                 :             :         else
     175                 :             :         {
     176                 :          60 :             Formatter_WriteBytes(formatter, REPLACEMENT_CHARACTER, sizeof(REPLACEMENT_CHARACTER));
     177                 :          60 :             len += 1U;
     178                 :             :         }
     179                 :             :     }
     180                 :       63315 :     Formatter_NullTerminate(formatter);
     181                 :       63315 : }
     182                 :             : 
     183                 :      553042 : static inline bool Formatter_CodepointFits(size_t codepointLength, size_t remainingDecodedLength)
     184                 :             : {
     185   [ +  +  +  + ]:      553042 :     return (codepointLength > 0U) && (codepointLength <= remainingDecodedLength);
     186                 :             : }
     187                 :             : 
     188                 :      577695 : static inline size_t Formatter_Utf8CodepointLength(const char* source)
     189                 :             : {
     190                 :      577695 :     size_t length = 0U;
     191                 :             : 
     192         [ +  + ]:      577695 :     if (SolidSyslogUtf8_IsAsciiByte(source[0]))
     193                 :             :     {
     194                 :      577596 :         length = 1;
     195                 :             :     }
     196   [ +  +  +  + ]:          99 :     else if ((source[1] != '\0') && Formatter_IsValidUtf8TwoByte(source[0], source[1]))
     197                 :             :     {
     198                 :          11 :         length = 2;
     199                 :             :     }
     200   [ +  +  +  +  :         132 :     else if ((source[1] != '\0') && (source[2] != '\0') &&
                   +  + ]
     201                 :          44 :              Formatter_IsValidUtf8ThreeByte(source[0], source[1], source[2]))
     202                 :             :     {
     203                 :          10 :         length = 3;
     204                 :             :     }
     205   [ +  +  +  +  :          98 :     else if ((source[1] != '\0') && (source[2] != '\0') && (source[3] != '\0') &&
             +  +  +  + ]
     206                 :          20 :              Formatter_IsValidUtf8FourByte(source[0], source[1], source[2], source[3]))
     207                 :             :     {
     208                 :          11 :         length = 4;
     209                 :             :     }
     210                 :             :     else
     211                 :             :     {
     212                 :             :         /* lead does not start a valid 1-/2-/3-/4-byte UTF-8 sequence - length stays 0 */
     213                 :             :     }
     214                 :             : 
     215                 :      577695 :     return length;
     216                 :             : }
     217                 :             : 
     218                 :          70 : static inline bool Formatter_IsValidUtf8TwoByte(char lead, char continuation1)
     219                 :             : {
     220   [ +  +  +  +  :          82 :     return SolidSyslogUtf8_IsTwoByteLead(lead) && !Formatter_IsOverlongTwoByteLead(lead) &&
                   +  + ]
     221                 :          12 :            SolidSyslogUtf8_IsContinuationByte(continuation1);
     222                 :             : }
     223                 :             : 
     224                 :          15 : static inline bool Formatter_IsOverlongTwoByteLead(char byte)
     225                 :             : {
     226                 :          15 :     return ((unsigned char) byte & 0xFEU) == 0xC0U;
     227                 :             : }
     228                 :             : 
     229                 :          44 : static inline bool Formatter_IsValidUtf8ThreeByte(char lead, char continuation1, char continuation2)
     230                 :             : {
     231   [ +  +  +  + ]:          74 :     return SolidSyslogUtf8_IsThreeByteLead(lead) && SolidSyslogUtf8_IsContinuationByte(continuation1) &&
     232                 :          14 :            SolidSyslogUtf8_IsContinuationByte(continuation2) &&
     233   [ +  +  +  + ]:          71 :            !Formatter_IsOverlongThreeByteEncoding(lead, continuation1) &&
     234         [ +  + ]:          11 :            !Formatter_IsUtf16SurrogateEncoding(lead, continuation1);
     235                 :             : }
     236                 :             : 
     237                 :          13 : static inline bool Formatter_IsOverlongThreeByteEncoding(char lead, char continuation1)
     238                 :             : {
     239   [ +  +  +  + ]:          13 :     return ((unsigned char) lead == 0xE0U) && (((unsigned char) continuation1 & 0xE0U) == 0x80U);
     240                 :             : }
     241                 :             : 
     242                 :          11 : static inline bool Formatter_IsUtf16SurrogateEncoding(char lead, char continuation1)
     243                 :             : {
     244   [ +  +  +  + ]:          11 :     return ((unsigned char) lead == 0xEDU) && (((unsigned char) continuation1 & 0xE0U) == 0xA0U);
     245                 :             : }
     246                 :             : 
     247                 :          20 : static inline bool Formatter_IsValidUtf8FourByte(char lead, char continuation1, char continuation2, char continuation3)
     248                 :             : {
     249   [ +  +  +  + ]:          57 :     return SolidSyslogUtf8_IsFourByteLead(lead) && SolidSyslogUtf8_IsContinuationByte(continuation1) &&
     250         [ +  + ]:          35 :            SolidSyslogUtf8_IsContinuationByte(continuation2) && SolidSyslogUtf8_IsContinuationByte(continuation3) &&
     251   [ +  +  +  + ]:          54 :            !Formatter_IsOverlongFourByteEncoding(lead, continuation1) &&
     252         [ +  + ]:          15 :            !Formatter_IsAboveUnicodeMaxEncoding(lead, continuation1);
     253                 :             : }
     254                 :             : 
     255                 :          16 : static inline bool Formatter_IsOverlongFourByteEncoding(char lead, char continuation1)
     256                 :             : {
     257   [ +  +  +  + ]:          16 :     return ((unsigned char) lead == 0xF0U) && (((unsigned char) continuation1 & 0xF0U) == 0x80U);
     258                 :             : }
     259                 :             : 
     260                 :             : /* NOLINTBEGIN(bugprone-easily-swappable-parameters) -- lead and continuation1 are byte values with distinct semantic roles, swap would not even compile a different result given the lead's value constraint */
     261                 :          15 : static inline bool Formatter_IsAboveUnicodeMaxEncoding(char lead, char continuation1)
     262                 :             : {
     263                 :          15 :     unsigned char uLead = (unsigned char) lead;
     264   [ +  +  +  + ]:          15 :     bool f4WithCont1Above8F = (uLead == 0xF4U) && (((unsigned char) continuation1 & 0xF0U) != 0x80U);
     265   [ +  +  +  - ]:          15 :     bool f5OrHigherLead = (uLead >= 0xF5U) && (uLead <= 0xF7U);
     266   [ +  +  +  + ]:          15 :     return f4WithCont1Above8F || f5OrHigherLead;
     267                 :             : }
     268                 :             : 
     269                 :             : /* NOLINTEND(bugprone-easily-swappable-parameters) */
     270                 :             : 
     271                 :      584422 : static inline void Formatter_WriteBytes(struct SolidSyslogFormatter* formatter, const char* bytes, size_t count)
     272                 :             : {
     273         [ +  + ]:     1182333 :     for (size_t i = 0U; i < count; i++)
     274                 :             :     {
     275                 :      597911 :         Formatter_WriteChar(formatter, bytes[i]);
     276                 :             :     }
     277                 :      584422 : }
     278                 :             : 
     279                 :       22354 : void SolidSyslogFormatter_EscapedString(
     280                 :             :     struct SolidSyslogFormatter* formatter,
     281                 :             :     const char* source,
     282                 :             :     size_t maxDecodedLength
     283                 :             : )
     284                 :             : {
     285                 :       22354 :     struct EscapedContext context = {
     286                 :             :         .Formatter = formatter,
     287                 :             :         .Source = source,
     288                 :             :         .SourcePos = 0,
     289                 :             :         .DecodedLength = 0,
     290                 :             :         .MaxDecodedLength = maxDecodedLength,
     291                 :             :         .Exhausted = false,
     292                 :             :     };
     293                 :             : 
     294         [ +  + ]:       47185 :     while (!Formatter_IsExhausted(&context))
     295                 :             :     {
     296         [ +  + ]:       24831 :         if (Formatter_NeedsEscape(source[context.SourcePos]))
     297                 :             :         {
     298                 :         178 :             Formatter_WriteEscaped(&context);
     299                 :             :         }
     300                 :             :         else
     301                 :             :         {
     302                 :       24653 :             Formatter_WriteCodepoint(&context);
     303                 :             :         }
     304                 :             :     }
     305                 :       22354 :     Formatter_NullTerminate(formatter);
     306                 :       22354 : }
     307                 :             : 
     308                 :       24831 : static inline bool Formatter_NeedsEscape(char value)
     309                 :             : {
     310                 :             :     static const char QUOTE = '"';
     311                 :             :     static const char BACKSLASH = '\\';
     312                 :             :     static const char CLOSE_BRACKET = ']';
     313   [ +  +  +  +  :       24831 :     return (value == QUOTE) || (value == BACKSLASH) || (value == CLOSE_BRACKET);
                   +  + ]
     314                 :             : }
     315                 :             : 
     316                 :       47185 : static inline bool Formatter_IsExhausted(const struct EscapedContext* context)
     317                 :             : {
     318   [ +  +  +  + ]:       47185 :     return context->Exhausted || (context->Source[context->SourcePos] == (char) '\0');
     319                 :             : }
     320                 :             : 
     321                 :         178 : static inline void Formatter_WriteEscaped(struct EscapedContext* context)
     322                 :             : {
     323                 :             :     static const char ESCAPE_PREFIX = '\\';
     324                 :             :     /* An escape pair on the wire ('\' + char) decodes back to the single
     325                 :             :      * character it was escaping - one byte in the reader's decoder buffer. */
     326                 :             :     static const size_t ESCAPED_CHARACTER_DECODED_LENGTH = 1;
     327         [ +  + ]:         178 :     if (Formatter_Fits(context, ESCAPED_CHARACTER_DECODED_LENGTH))
     328                 :             :     {
     329                 :         177 :         char escaped[] = {ESCAPE_PREFIX, context->Source[context->SourcePos]};
     330                 :         177 :         Formatter_WriteContext(context, escaped, sizeof(escaped), 1, ESCAPED_CHARACTER_DECODED_LENGTH);
     331                 :             :     }
     332                 :             :     else
     333                 :             :     {
     334                 :           1 :         Formatter_Exhaust(context);
     335                 :             :     }
     336                 :         178 : }
     337                 :             : 
     338                 :       24848 : static inline bool Formatter_Fits(const struct EscapedContext* context, size_t decodedAdvance)
     339                 :             : {
     340   [ +  +  +  + ]:       24848 :     return (decodedAdvance > 0U) && (decodedAdvance <= (context->MaxDecodedLength - context->DecodedLength));
     341                 :             : }
     342                 :             : 
     343                 :             : /* NOLINTBEGIN(bugprone-easily-swappable-parameters) -- see forward declaration */
     344                 :       24822 : static inline void Formatter_WriteContext(
     345                 :             :     struct EscapedContext* context,
     346                 :             :     const char* bytes,
     347                 :             :     size_t byteCount,
     348                 :             :     size_t sourceAdvance,
     349                 :             :     size_t decodedAdvance
     350                 :             : )
     351                 :             : {
     352                 :       24822 :     Formatter_WriteBytes(context->Formatter, bytes, byteCount);
     353                 :       24822 :     context->SourcePos += sourceAdvance;
     354                 :       24822 :     context->DecodedLength += decodedAdvance;
     355                 :       24822 : }
     356                 :             : 
     357                 :             : /* NOLINTEND(bugprone-easily-swappable-parameters) */
     358                 :             : 
     359                 :           9 : static inline void Formatter_Exhaust(struct EscapedContext* context)
     360                 :             : {
     361                 :           9 :     context->Exhausted = true;
     362                 :           9 : }
     363                 :             : 
     364                 :             : /* Writes the source codepoint at sourcePos if it fits the decoded budget;
     365                 :             :  * otherwise falls back to Formatter_WriteReplacement (which emits U+FFFD or marks
     366                 :             :  * the context exhausted). Formatter_Fits also rejects invalid UTF-8 because
     367                 :             :  * Formatter_Utf8CodepointLength returns 0 for ill-formed sequences. */
     368                 :       24653 : static inline void Formatter_WriteCodepoint(struct EscapedContext* context)
     369                 :             : {
     370                 :       24653 :     size_t codepointLength = Formatter_Utf8CodepointLength(&context->Source[context->SourcePos]);
     371         [ +  + ]:       24653 :     if (Formatter_Fits(context, codepointLength))
     372                 :             :     {
     373                 :       24636 :         Formatter_WriteContext(
     374                 :             :             context,
     375                 :       24636 :             &context->Source[context->SourcePos],
     376                 :             :             codepointLength,
     377                 :             :             codepointLength,
     378                 :             :             codepointLength
     379                 :             :         );
     380                 :             :     }
     381                 :             :     else
     382                 :             :     {
     383                 :          17 :         Formatter_WriteReplacement(context);
     384                 :             :     }
     385                 :       24653 : }
     386                 :             : 
     387                 :          17 : static inline void Formatter_WriteReplacement(struct EscapedContext* context)
     388                 :             : {
     389         [ +  + ]:          17 :     if (Formatter_Fits(context, sizeof(REPLACEMENT_CHARACTER)))
     390                 :             :     {
     391                 :           9 :         Formatter_WriteContext(
     392                 :             :             context,
     393                 :             :             REPLACEMENT_CHARACTER,
     394                 :             :             sizeof(REPLACEMENT_CHARACTER),
     395                 :             :             1,
     396                 :             :             sizeof(REPLACEMENT_CHARACTER)
     397                 :             :         );
     398                 :             :     }
     399                 :             :     else
     400                 :             :     {
     401                 :           8 :         Formatter_Exhaust(context);
     402                 :             :     }
     403                 :          17 : }
     404                 :             : 
     405                 :       22280 : void SolidSyslogFormatter_PrintUsAsciiString(
     406                 :             :     struct SolidSyslogFormatter* formatter,
     407                 :             :     const char* source,
     408                 :             :     size_t maxLength
     409                 :             : )
     410                 :             : {
     411                 :       22280 :     size_t len = 0U;
     412                 :             : 
     413   [ +  +  +  + ]:      162884 :     while ((len < maxLength) && (source[len] != '\0'))
     414                 :             :     {
     415                 :      140604 :         Formatter_WritePrintableUsAsciiChar(formatter, source[len]);
     416                 :      140604 :         len++;
     417                 :             :     }
     418                 :       22280 :     Formatter_NullTerminate(formatter);
     419                 :       22280 : }
     420                 :             : 
     421                 :      140604 : static inline void Formatter_WritePrintableUsAsciiChar(struct SolidSyslogFormatter* formatter, char value)
     422                 :             : {
     423         [ +  + ]:      140604 :     if (Formatter_IsPrintableUsAscii(value))
     424                 :             :     {
     425                 :      140594 :         Formatter_WriteChar(formatter, value);
     426                 :             :     }
     427                 :             :     else
     428                 :             :     {
     429                 :          10 :         Formatter_WriteChar(formatter, NON_PRINTABLE_SUBSTITUTE);
     430                 :             :     }
     431                 :      140604 : }
     432                 :             : 
     433                 :      227204 : static inline bool Formatter_IsPrintableUsAscii(char value)
     434                 :             : {
     435                 :             :     static const char LOWEST_PRINTABLE_US_ASCII = '!';
     436                 :             :     static const char HIGHEST_PRINTABLE_US_ASCII = '~';
     437   [ +  +  +  + ]:      227204 :     return (value >= LOWEST_PRINTABLE_US_ASCII) && (value <= HIGHEST_PRINTABLE_US_ASCII);
     438                 :             : }
     439                 :             : 
     440                 :       16923 : void SolidSyslogFormatter_Uint32(struct SolidSyslogFormatter* formatter, uint32_t value)
     441                 :             : {
     442                 :       16923 :     size_t digits = Formatter_CountDigits(value);
     443                 :       16923 :     uint32_t divisor = 1;
     444                 :       16923 :     uint32_t remaining = value;
     445                 :             : 
     446         [ +  + ]:       36693 :     for (size_t i = 1; i < digits; i++)
     447                 :             :     {
     448                 :       19770 :         divisor *= 10U;
     449                 :             :     }
     450                 :             : 
     451         [ +  + ]:       53616 :     for (size_t i = 0U; i < digits; i++)
     452                 :             :     {
     453                 :       36693 :         Formatter_WriteChar(formatter, Formatter_DigitToChar(remaining / divisor));
     454                 :       36693 :         remaining %= divisor;
     455                 :       36693 :         divisor /= 10U;
     456                 :             :     }
     457                 :       16923 :     Formatter_NullTerminate(formatter);
     458                 :       16923 : }
     459                 :             : 
     460                 :       16923 : static size_t Formatter_CountDigits(uint32_t value)
     461                 :             : {
     462                 :       16923 :     size_t count = 1;
     463                 :       16923 :     uint32_t remaining = value;
     464                 :             : 
     465         [ +  + ]:       36693 :     while (remaining >= 10U)
     466                 :             :     {
     467                 :       19770 :         count++;
     468                 :       19770 :         remaining /= 10U;
     469                 :             :     }
     470                 :             : 
     471                 :       16923 :     return count;
     472                 :             : }
     473                 :             : 
     474                 :       92099 : static inline char Formatter_DigitToChar(uint32_t value)
     475                 :             : {
     476                 :       92099 :     return (char) ('0' + (value % 10U));
     477                 :             : }
     478                 :             : 
     479                 :       27568 : void SolidSyslogFormatter_TwoDigit(struct SolidSyslogFormatter* formatter, uint32_t value)
     480                 :             : {
     481                 :       27568 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 10U));
     482                 :       27568 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value));
     483                 :       27568 :     Formatter_NullTerminate(formatter);
     484                 :       27568 : }
     485                 :             : 
     486                 :          27 : void SolidSyslogFormatter_FourDigit(struct SolidSyslogFormatter* formatter, uint32_t value)
     487                 :             : {
     488                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 1000U));
     489                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 100U));
     490                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 10U));
     491                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value));
     492                 :          27 :     Formatter_NullTerminate(formatter);
     493                 :          27 : }
     494                 :             : 
     495                 :          27 : void SolidSyslogFormatter_SixDigit(struct SolidSyslogFormatter* formatter, uint32_t value)
     496                 :             : {
     497                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 100000U));
     498                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 10000U));
     499                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 1000U));
     500                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 100U));
     501                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value / 10U));
     502                 :          27 :     Formatter_WriteChar(formatter, Formatter_DigitToChar(value));
     503                 :          27 :     Formatter_NullTerminate(formatter);
     504                 :          27 : }
     505                 :             : 
     506                 :       39200 : const char* SolidSyslogFormatter_AsFormattedBuffer(struct SolidSyslogFormatter* formatter)
     507                 :             : {
     508                 :       39200 :     Formatter_TrimTruncatedMultiByteTail(formatter);
     509                 :       39200 :     return formatter->Buffer;
     510                 :             : }
     511                 :             : 
     512                 :       39200 : static inline void Formatter_TrimTruncatedMultiByteTail(struct SolidSyslogFormatter* formatter)
     513                 :             : {
     514                 :       39200 :     char* buffer = formatter->Buffer;
     515                 :       39200 :     size_t p = formatter->Position;
     516                 :       39200 :     size_t trimFrom = p;
     517                 :             : 
     518   [ +  +  +  + ]:       76790 :     if ((p >= 1U) &&
     519   [ +  +  +  + ]:      112766 :         (SolidSyslogUtf8_IsTwoByteLead(buffer[p - 1U]) || SolidSyslogUtf8_IsThreeByteLead(buffer[p - 1U]) ||
     520                 :       37587 :          SolidSyslogUtf8_IsFourByteLead(buffer[p - 1U])))
     521                 :             :     {
     522                 :           4 :         trimFrom = p - 1U;
     523                 :             :     }
     524   [ +  +  +  + ]:       76759 :     else if ((p >= 2U) &&
     525         [ +  + ]:       75123 :              (SolidSyslogUtf8_IsThreeByteLead(buffer[p - 2U]) || SolidSyslogUtf8_IsFourByteLead(buffer[p - 2U])))
     526                 :             :     {
     527                 :           5 :         trimFrom = p - 2U;
     528                 :             :     }
     529   [ +  +  +  + ]:       39191 :     else if ((p >= 3U) && SolidSyslogUtf8_IsFourByteLead(buffer[p - 3U]))
     530                 :             :     {
     531                 :           2 :         trimFrom = p - 3U;
     532                 :             :     }
     533                 :             :     else
     534                 :             :     {
     535                 :             :         /* tail does not look like a truncated multi-byte sequence - trim nothing */
     536                 :             :     }
     537         [ +  + ]:       39220 :     for (size_t i = trimFrom; i < p; i++)
     538                 :             :     {
     539                 :          20 :         buffer[i] = '\0';
     540                 :             :     }
     541                 :       39200 : }
     542                 :             : 
     543                 :       76964 : size_t SolidSyslogFormatter_Length(const struct SolidSyslogFormatter* formatter)
     544                 :             : {
     545                 :       76964 :     return formatter->Position;
     546                 :             : }
     547                 :             : 
     548                 :             : /* cppcheck-suppress constParameterPointer -- hands back the storage for the caller to write through. */
     549                 :         453 : char* SolidSyslogFormatter_Bytes(struct SolidSyslogFormatter* formatter)
     550                 :             : {
     551                 :         453 :     return formatter->Buffer;
     552                 :             : }
        

Generated by: LCOV version 2.0-1