LCOV - code coverage report
Current view: top level - protobuf-c-text - parse.c (source / functions) Hit Total Coverage
Test: PB-C-TEXT Code Coverage Lines: 129 144 89.6 %
Date: 2014-09-08 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Generated by re2c 0.13.5 on Mon Sep  8 17:03:26 2014 */
       2             : #line 1 "protobuf-c-text/parse.re"
       3             : /* c-basic-offset: 2; tab-width: 8; indent-tabs-mode: nil; mode: c
       4             :  * vi: set shiftwidth=2 tabstop=8 expandtab filetype=c:
       5             :  * :indentSize=2:tabSize=8:noTabs=true:mode=c:
       6             :  */
       7             : 
       8             : /** \file
       9             :  * Routines to parse text format protobufs.
      10             :  *
      11             :  * This file contains the internal support functions as well as the
      12             :  * exported functions which are used to parse text format protobufs
      13             :  * into C protobuf data types.
      14             :  *
      15             :  * Note that this file must first be pre-processed with \c re2c.  The
      16             :  * build system does this for you, but the manual step is as follows:
      17             :  *
      18             :  * \code
      19             :  * re2c -s -o protobuf-c-text/parse.c protobuf-c-text/parse.re
      20             :  * \endcode
      21             :  *
      22             :  * \author Kevin Lyda <kevin@ie.suberic.net>
      23             :  * \date   March 2014
      24             :  */
      25             : 
      26             : #include <errno.h>
      27             : #include <stdarg.h>
      28             : #include <stdbool.h>
      29             : #include <stdint.h>
      30             : #include <stdio.h>
      31             : #include <stdlib.h>
      32             : #include <string.h>
      33             : #include <unistd.h>
      34             : #include <protobuf-c/protobuf-c.h>
      35             : #include "protobuf-c-text.h"
      36             : #include "protobuf-c-util.h"
      37             : #include "config.h"
      38             : 
      39             : /** \defgroup utility Utility functions
      40             :  * \ingroup internal
      41             :  * @{
      42             :  */
      43             : 
      44             : /** A realloc implementation using ProtobufCAllocator functions.
      45             :  *
      46             :  * Similar to \c realloc, but using ProtobufCAllocator functions to do the
      47             :  * memory manipulations.
      48             :  *
      49             :  * \param[in,out] ptr Memory to realloc.
      50             :  * \param[in] old_size The size of ptr before realloc.
      51             :  * \param[in] size The desired size of ptr after realloc.
      52             :  * \param[in] allocator The functions to use to achieve this.
      53             :  * \return \c NULL on realloc failure - note \c ptr isn't freed in this
      54             :  *         case.  The new, \c size sized pointer (and \c ptr is freed in
      55             :  *         this case).
      56             :  */
      57             : static void *
      58             : local_realloc(void *ptr,
      59             :     size_t old_size,
      60             :     size_t size,
      61             :     ProtobufCAllocator *allocator)
      62             : {
      63             :   void *tmp;
      64             : 
      65             :   tmp = PBC_ALLOC(size);
      66             :   if (!tmp) {
      67             :     return NULL;
      68             :   }
      69             :   if (old_size < size) {
      70             :     /* Extending. */
      71             :     memcpy(tmp, ptr, old_size);
      72             :   } else {
      73             :     /* Truncating. */
      74             :     memcpy(tmp, ptr, size);
      75             :   }
      76             : 
      77             :   PBC_FREE(ptr);
      78             :   return tmp;
      79             : }
      80             : 
      81             : /** @} */  /* End of utility group. */
      82             : 
      83             : /** \defgroup lexer Routines related to lexing text format protobufs
      84             :  * \ingroup internal
      85             :  * @{
      86             :  */
      87             : 
      88             : /** Token types.
      89             :  *
      90             :  * Types of tokens found by scan(). These will be in the \c id
      91             :  * field of \c Token .
      92             :  */
      93             : typedef enum {
      94             :   TOK_EOF,        /**< End of file. */
      95             :   TOK_BAREWORD,   /**< A bare, unquoted single word. */
      96             :   TOK_OBRACE,     /**< An opening brace. */
      97             :   TOK_CBRACE,     /**< A closing brace. */
      98             :   TOK_COLON,      /**< A colon. */
      99             :   TOK_QUOTED,     /**< A quoted string. */
     100             :   TOK_NUMBER,     /**< A number. */
     101             :   TOK_BOOLEAN,    /**< The unquoted form of "true" and "false". */
     102             :   TOK_MALLOC_ERR  /**< A memory allocation error occurred. */
     103             : } TokenId;
     104             : 
     105             : /** A token and its value.
     106             :  *
     107             :  * A \c Token found by scan().  It contains the \c TokenId and the
     108             :  * value of the token found (if a value is relevant).
     109             :  */
     110             : typedef struct _Token {
     111             :   TokenId id;        /**< The kind of token. */
     112             :   union {
     113             :     char *number;    /**< \b TOK_NUMBER: string with the number. */
     114             :     char *bareword;  /**< \b TOK_BAREWORD: string with bareword in it. */
     115             :     ProtobufCBinaryData *qs; /**< \b TOK_QUOTED: Unescaped quoted string
     116             :                                with the quotes removed. */
     117             :     bool boolean;    /**< \b TOK_BOOLEAN: \c true or \c false . */
     118             :   };
     119             : } Token;
     120             : 
     121             : /** Converts a Token to a string based on its type.
     122             :  *
     123             :  * Provides a string summary of the type of token; used for error messages.
     124             :  *
     125             :  * \param[in] t The token.
     126             :  * \return A string representation of the token. This is a char * on the stack.
     127             :  *         Do not modify or free it.
     128             :  */
     129             : static const char *
     130             : token2txt(Token *t)
     131             : {
     132             :   switch (t->id) {
     133             :     case TOK_EOF:
     134             :       return "[EOF]"; break;
     135             :     case TOK_BAREWORD:
     136             :       return t->bareword; break;
     137             :     case TOK_OBRACE:
     138             :       return "{"; break;
     139             :     case TOK_CBRACE:
     140             :       return "}"; break;
     141             :     case TOK_COLON:
     142             :       return ":"; break;
     143             :     case TOK_QUOTED:
     144             :       return "[string]"; break;
     145             :     case TOK_NUMBER:
     146             :       return t->number; break;
     147             :     case TOK_BOOLEAN:
     148             :       return t->boolean? "true": "false"; break;
     149             :     default:
     150             :       return "[UNKNOWN]"; break;
     151             :   }
     152             : }
     153             : 
     154             : /** Frees memory allocated in a \c Token instance.
     155             :  *
     156             :  * Frees memory allocated in a \c Token instance, but not
     157             :  * the \c Token itself.
     158             :  *
     159             :  * \param[in] t The token.
     160             :  * \param[in] allocator The memory allocator functions.
     161             :  */
     162             : static void
     163             : token_free(Token *t, ProtobufCAllocator *allocator)
     164             : {
     165             :   switch (t->id) {
     166             :     case TOK_BAREWORD:
     167             :       PBC_FREE(t->bareword);
     168             :       break;
     169             :     case TOK_QUOTED:
     170             :       PBC_FREE(t->qs->data);
     171             :       break;
     172             :     case TOK_NUMBER:
     173             :       PBC_FREE(t->number);
     174             :       break;
     175             :     default:
     176             :       break;
     177             :   }
     178             : }
     179             : 
     180             : /** Maintains state for successive calls to scan() .
     181             :  *
     182             :  * This structure is used by the scanner to maintain state.
     183             :  */
     184             : typedef struct _Scanner {
     185             :   unsigned char *cursor; /**< Where we are in the \c buffer. */
     186             :   unsigned char *marker; /**< Used for backtracking. */
     187             :   unsigned char *buffer; /**< The buffer holding the data being parsed. */
     188             :   unsigned char *limit;  /**< Where the buffer ends. */
     189             :   unsigned char *token;  /**< Pointer to the start of the current token. */
     190             :   FILE *f;  /**< For file scanners, this is the input source.  Data read
     191             :               from it is put in \c buffer. */
     192             :   int line; /**< Current line number being parsed. Used for error
     193             :               reporting. */
     194             : } Scanner;
     195             : 
     196             : /** Initialise a \c Scanner from a \c FILE
     197             :  *
     198             :  * The resulting \c Scanner will load input from a \c FILE.
     199             :  *
     200             :  * \param[in,out] scanner The state struct for the scanner.
     201             :  * \param[in] f \c FILE to read input from.
     202             :  */
     203             : static void
     204             : scanner_init_file(Scanner *scanner, FILE *f)
     205             : {
     206             :   memset(scanner, 0, sizeof(Scanner));
     207             :   scanner->f = f;
     208             :   scanner->line = 1;
     209             : }
     210             : 
     211             : /** Initialise a \c Scanner from a string.
     212             :  *
     213             :  * The resulting \c Scanner will load input from a string.
     214             :  *
     215             :  * \param[in,out] scanner The state struct for the scanner.
     216             :  * \param[in] buf String to get input from.
     217             :  */
     218             : static void
     219             : scanner_init_string(Scanner *scanner, char *buf)
     220             : {
     221             :   memset(scanner, 0, sizeof(Scanner));
     222             :   scanner->buffer = buf;
     223             :   scanner->marker = buf;
     224             :   scanner->cursor = buf;
     225             :   scanner->limit = &buf[strlen(buf)];
     226             :   scanner->line = 1;
     227             : }
     228             : 
     229             : /** Free data internal to the \c Scanner instance.
     230             :  *
     231             :  * \param[in,out] scanner The state struct for the scanner.
     232             :  * \param[in] allocator Allocator functions.
     233             :  */
     234             : static void
     235             : scanner_free(Scanner *scanner, ProtobufCAllocator *allocator)
     236             : {
     237             :   if (scanner->f && scanner->buffer)
     238             :     PBC_FREE(scanner->buffer);
     239             :   scanner->buffer = NULL;
     240             : }
     241             : 
     242             : /** Unescape string.
     243             :  *
     244             :  * Remove escape sequences from a string and replace them with the
     245             :  * actual characters.
     246             :  *
     247             :  * \param[in] src String to unescape.
     248             :  * \param[in] len Length of string to unescape.
     249             :  * \param[in] allocator Allocator functions.
     250             :  * \return A ProtobufCBinaryData pointer with the unescaped data.
     251             :  *         Note this must be freed with the ProtobufCAllocator
     252             :  *         allocator you called this with.
     253             :  */
     254             : static ProtobufCBinaryData *
     255             : unesc_str(unsigned char *src, int len, ProtobufCAllocator *allocator)
     256             : {
     257             :   ProtobufCBinaryData *dst_pbbd;
     258             :   unsigned char *dst;
     259             :   int i = 0, dst_len = 0;
     260             :   unsigned char oct[4];
     261             : 
     262             :   dst_pbbd = PBC_ALLOC(sizeof(ProtobufCBinaryData));
     263             :   dst = PBC_ALLOC(len + 1);
     264             :   if (!dst_pbbd || !dst) {
     265             :     goto unesc_str_error;
     266             :   }
     267             :   oct[3] = '\0';
     268             : 
     269             :   while (i < len) {
     270             :     if (src[i] != '\\') {
     271             :       dst[dst_len++] = src[i++];
     272             :     } else {
     273             :       i++;
     274             :       if (i == len) {
     275             :         /* Fell off the end of the string after \. */
     276             :         goto unesc_str_error;
     277             :       }
     278             :       switch (src[i]) {
     279             :         case '0':
     280             :           if (i + 2 < len
     281             :               && (src[i+1] >= '0' && src[i+1] <= '7')
     282             :               && (src[i+2] >= '0' && src[i+2] <= '7')) {
     283             :             memcpy(oct, src + i, 3);
     284             :             dst[dst_len++] = (unsigned char)strtoul(oct, NULL, 8);
     285             :             i += 2;  /* Gets incremented again down below. */
     286             :           } else {
     287             :             /* Decoding a \0 failed or was cut off.. */
     288             :             goto unesc_str_error;
     289             :           }
     290             :           break;
     291             :         case '\'':
     292             :           dst[dst_len++] = '\'';
     293             :           break;
     294             :         case '\"':
     295             :           dst[dst_len++] = '\"';
     296             :           break;
     297             :         case '\\':
     298             :           dst[dst_len++] = '\\';
     299             :           break;
     300             :         case 'n':
     301             :           dst[dst_len++] = '\n';
     302             :           break;
     303             :         case 'r':
     304             :           dst[dst_len++] = '\r';
     305             :           break;
     306             :         case 't':
     307             :           dst[dst_len++] = '\t';
     308             :           break;
     309             :         default:
     310             :           goto unesc_str_error;
     311             :           break;
     312             :       }
     313             :       i++;
     314             :     }
     315             :   }
     316             : 
     317             :   dst_pbbd->data = dst;
     318             :   dst_pbbd->len = dst_len;
     319             :   return dst_pbbd;
     320             : 
     321             : unesc_str_error:
     322             :   PBC_FREE(dst);
     323             :   PBC_FREE(dst_pbbd);
     324             :   return NULL;
     325             : }
     326             : 
     327             : /** Amount of data to read from a file each time. */
     328             : #define CHUNK 4096
     329             : 
     330             : /** Function to request more data from input source in \c Scanner.
     331             :  *
     332             :  * In the case of a string being the input source for \c Scanner,
     333             :  * nothing happens. For a \c FILE backed \c Scanner, a \c CHUNK's
     334             :  * worth of data is read from the \c FILE.
     335             :  *
     336             :  * \param[in,out] scanner The state struct for the scanner.
     337             :  * \param[in] allocator Allocator functions.
     338             :  * \return Returns the success of the function:
     339             :  *         - -1: Memory allocation failure.
     340             :  *         - 0: No more input added.
     341             :  *         - >0: Input added.
     342             :  */
     343             : static int
     344             : fill(Scanner *scanner, ProtobufCAllocator *allocator)
     345             : {
     346             :   char *buf;
     347             :   int len, oldlen, nmemb;
     348             : 
     349             :   if (scanner->token > scanner->limit) {
     350             :     /* this shouldn't happen */
     351             :     return 0;
     352             :   }
     353             :   if (scanner->f && !feof(scanner->f)) {
     354             :     oldlen = scanner->limit - scanner->token;
     355             :     len = CHUNK + oldlen;
     356             :     buf = PBC_ALLOC(len);
     357             :     if (!buf) {
     358             :       return -1;
     359             :     }
     360             :     memcpy(buf, scanner->token, oldlen);
     361             :     nmemb = fread(buf + oldlen, 1, CHUNK, scanner->f);
     362             :     if (nmemb != CHUNK) {
     363             :       /* Short read.  eof.  Append nul. */
     364             :       len = oldlen + nmemb;
     365             :       buf[len] = '\0';
     366             :     }
     367             :     /* Reset the world to use buf. */
     368             :     scanner->cursor = &buf[scanner->cursor - scanner->token];
     369             :     scanner->limit = buf + len;
     370             :     scanner->token = buf;
     371             :     PBC_FREE(scanner->buffer);
     372             :     scanner->buffer = buf;
     373             :     scanner->marker = buf;
     374             :   }
     375             : 
     376             :   return scanner->limit >= scanner->cursor? 1: 0;
     377             : }
     378             : 
     379             : /** Return the token. */
     380             : #define RETURN(tt) { t.id = tt; return t; }
     381             : /** Retrieves more input if available. */
     382             : #define YYFILL(n) { fill_result = fill(scanner, allocator); \
     383             :                     if (fill_result <= 0) \
     384             :                       RETURN((fill_result == -1? TOK_MALLOC_ERR: TOK_EOF)); }
     385             : 
     386             : /** Generated lexer.
     387             :  *
     388             :  * The guts of the parser generated by \c re2c.
     389             :  *
     390             :  * \param[in,out] scanner The state struct for the scanner.
     391             :  * \param[in] allocator Allocator functions.
     392             :  * \return Returns the next \c Token it finds.
     393             :  */
     394             : static Token
     395             : scan(Scanner *scanner, ProtobufCAllocator *allocator)
     396             : {
     397             :   Token t;
     398             :   int fill_result;
     399             : 
     400             : token_start:
     401             :   scanner->token = scanner->cursor;
     402             : 
     403             :   /* I don't think multiline strings are allowed.  If I'm wrong,
     404             :    * the QS re should be ["] (EQ|[^"]|NL)* ["]; */
     405             : 
     406             :   
     407             : #line 408 "protobuf-c-text/parse.c"
     408             : {
     409             :         unsigned char yych;
     410       45444 :         unsigned int yyaccept = 0;
     411             : 
     412       45444 :         if ((scanner->limit - scanner->cursor) < 6) YYFILL(6);
     413       45442 :         yych = *scanner->cursor;
     414       45442 :         if (yych <= ':') {
     415       36472 :                 if (yych <= '!') {
     416       23528 :                         if (yych <= '\t') {
     417           9 :                                 if (yych <= 0x00) goto yy25;
     418           0 :                                 if (yych >= '\t') goto yy21;
     419             :                         } else {
     420       23519 :                                 if (yych <= '\n') goto yy23;
     421       16018 :                                 if (yych == ' ') goto yy21;
     422             :                         }
     423             :                 } else {
     424       12944 :                         if (yych <= '-') {
     425        2165 :                                 if (yych <= '"') goto yy13;
     426         761 :                                 if (yych >= '-') goto yy3;
     427             :                         } else {
     428       10779 :                                 if (yych <= '.') goto yy7;
     429       10779 :                                 if (yych <= '/') goto yy2;
     430       10779 :                                 if (yych <= '9') goto yy4;
     431        6766 :                                 goto yy19;
     432             :                         }
     433             :                 }
     434             :         } else {
     435        8970 :                 if (yych <= 'f') {
     436        1606 :                         if (yych <= '^') {
     437         286 :                                 if (yych <= '@') goto yy2;
     438         286 :                                 if (yych <= 'Z') goto yy11;
     439             :                         } else {
     440        1320 :                                 if (yych == '`') goto yy2;
     441        1320 :                                 if (yych <= 'e') goto yy11;
     442         683 :                                 goto yy10;
     443             :                         }
     444             :                 } else {
     445        7364 :                         if (yych <= 'z') {
     446        6418 :                                 if (yych == 't') goto yy8;
     447        6104 :                                 goto yy11;
     448             :                         } else {
     449         946 :                                 if (yych <= '{') goto yy15;
     450         376 :                                 if (yych == '}') goto yy17;
     451             :                         }
     452             :                 }
     453             :         }
     454             : yy2:
     455           0 :         scanner->cursor = scanner->marker;
     456           0 :         if (yyaccept <= 0) {
     457           0 :                 goto yy6;
     458             :         } else {
     459           0 :                 goto yy30;
     460             :         }
     461             : yy3:
     462         761 :         yych = *++scanner->cursor;
     463         761 :         if (yych == '.') goto yy7;
     464         761 :         if (yych <= '/') goto yy2;
     465         761 :         if (yych <= '9') goto yy43;
     466           0 :         goto yy2;
     467             : yy4:
     468       12561 :         yyaccept = 0;
     469       12561 :         scanner->marker = ++scanner->cursor;
     470       12561 :         if ((scanner->limit - scanner->cursor) < 2) YYFILL(2);
     471       12561 :         yych = *scanner->cursor;
     472       12561 :         if (yych <= '@') {
     473       12560 :                 if (yych <= '.') {
     474        4011 :                         if (yych >= '.') goto yy7;
     475             :                 } else {
     476        8549 :                         if (yych <= '/') goto yy6;
     477        8549 :                         if (yych <= '9') goto yy4;
     478             :                 }
     479             :         } else {
     480           1 :                 if (yych <= '_') {
     481           1 :                         if (yych <= 'Z') goto yy11;
     482           0 :                         if (yych >= '_') goto yy11;
     483             :                 } else {
     484           0 :                         if (yych <= '`') goto yy6;
     485           0 :                         if (yych <= 'z') goto yy11;
     486             :                 }
     487             :         }
     488             : yy6:
     489             : #line 418 "protobuf-c-text/parse.re"
     490             :         {
     491             :                 t.number = PBC_ALLOC((scanner->cursor - scanner->token) + 1);
     492             :                 if (!t.number) {
     493             :                   RETURN(TOK_MALLOC_ERR);
     494             :                 }
     495             :                 memcpy(t.number, scanner->token,
     496             :                        scanner->cursor - scanner->token);
     497             :                 t.number[scanner->cursor - scanner->token] = '\0';
     498             :                 RETURN(TOK_NUMBER);
     499             :               }
     500             : #line 501 "protobuf-c-text/parse.c"
     501             : yy7:
     502         567 :         yych = *++scanner->cursor;
     503         567 :         if (yych <= '/') goto yy2;
     504         567 :         if (yych <= '9') goto yy41;
     505           0 :         goto yy2;
     506             : yy8:
     507         314 :         ++scanner->cursor;
     508         314 :         if ((yych = *scanner->cursor) == 'r') goto yy37;
     509         247 :         goto yy12;
     510             : yy9:
     511             : #line 430 "protobuf-c-text/parse.re"
     512             :         {
     513             :                 t.bareword = PBC_ALLOC((scanner->cursor - scanner->token) + 1);
     514             :                 if (!t.bareword) {
     515             :                   RETURN(TOK_MALLOC_ERR);
     516             :                 }
     517             :                 memcpy(t.bareword, scanner->token,
     518             :                        scanner->cursor - scanner->token);
     519             :                 t.bareword[scanner->cursor - scanner->token] = '\0';
     520             :                 RETURN(TOK_BAREWORD);
     521             :               }
     522             : #line 523 "protobuf-c-text/parse.c"
     523             : yy10:
     524         683 :         yych = *++scanner->cursor;
     525         683 :         if (yych == 'a') goto yy32;
     526         445 :         goto yy12;
     527             : yy11:
     528       75056 :         ++scanner->cursor;
     529       75056 :         if (scanner->limit <= scanner->cursor) YYFILL(1);
     530       75056 :         yych = *scanner->cursor;
     531             : yy12:
     532       75748 :         if (yych <= 'Z') {
     533       15727 :                 if (yych <= '/') goto yy9;
     534       14861 :                 if (yych <= '9') goto yy11;
     535        7715 :                 if (yych <= '@') goto yy9;
     536         857 :                 goto yy11;
     537             :         } else {
     538       60021 :                 if (yych <= '_') {
     539        9327 :                         if (yych <= '^') goto yy9;
     540        9327 :                         goto yy11;
     541             :                 } else {
     542       50694 :                         if (yych <= '`') goto yy9;
     543       50694 :                         if (yych <= 'z') goto yy11;
     544           0 :                         goto yy9;
     545             :                 }
     546             :         }
     547             : yy13:
     548       19635 :         ++scanner->cursor;
     549       19635 :         if (scanner->limit <= scanner->cursor) YYFILL(1);
     550       19634 :         yych = *scanner->cursor;
     551       19634 :         if (yych == '"') goto yy29;
     552       18231 :         if (yych == '\\') goto yy27;
     553       16061 :         goto yy13;
     554             : yy15:
     555         570 :         ++scanner->cursor;
     556             : #line 449 "protobuf-c-text/parse.re"
     557             :         { RETURN(TOK_OBRACE); }
     558             : #line 559 "protobuf-c-text/parse.c"
     559             : yy17:
     560         376 :         ++scanner->cursor;
     561             : #line 450 "protobuf-c-text/parse.re"
     562             :         { RETURN(TOK_CBRACE); }
     563             : #line 564 "protobuf-c-text/parse.c"
     564             : yy19:
     565        6766 :         ++scanner->cursor;
     566             : #line 451 "protobuf-c-text/parse.re"
     567             :         { RETURN(TOK_COLON); }
     568             : #line 569 "protobuf-c-text/parse.c"
     569             : yy21:
     570       16018 :         ++scanner->cursor;
     571             : #line 452 "protobuf-c-text/parse.re"
     572             :         { goto token_start; }
     573             : #line 574 "protobuf-c-text/parse.c"
     574             : yy23:
     575        7501 :         ++scanner->cursor;
     576             : #line 453 "protobuf-c-text/parse.re"
     577             :         { scanner->line++; goto token_start; }
     578             : #line 579 "protobuf-c-text/parse.c"
     579             : yy25:
     580           9 :         ++scanner->cursor;
     581             : #line 454 "protobuf-c-text/parse.re"
     582             :         { RETURN(TOK_EOF); }
     583             : #line 584 "protobuf-c-text/parse.c"
     584             : yy27:
     585        2324 :         ++scanner->cursor;
     586        2324 :         if (scanner->limit <= scanner->cursor) YYFILL(1);
     587        2324 :         yych = *scanner->cursor;
     588        2324 :         if (yych == '"') goto yy31;
     589        2181 :         if (yych == '\\') goto yy27;
     590        2028 :         goto yy13;
     591             : yy29:
     592        1403 :         ++scanner->cursor;
     593             : yy30:
     594             : #line 440 "protobuf-c-text/parse.re"
     595             :         {
     596             :                 t.qs = unesc_str(scanner->token + 1,
     597             :                                  scanner->cursor - scanner->token - 2,
     598             :                                  allocator);
     599             :                 if (!t.qs) {
     600             :                   RETURN(TOK_MALLOC_ERR);
     601             :                 }
     602             :                 RETURN(TOK_QUOTED);
     603             :               }
     604             : #line 605 "protobuf-c-text/parse.c"
     605             : yy31:
     606         143 :         yyaccept = 1;
     607         143 :         scanner->marker = ++scanner->cursor;
     608         143 :         if (scanner->limit <= scanner->cursor) YYFILL(1);
     609         143 :         yych = *scanner->cursor;
     610         143 :         if (yych == '"') goto yy29;
     611         143 :         if (yych == '\\') goto yy27;
     612         142 :         goto yy13;
     613             : yy32:
     614         238 :         yych = *++scanner->cursor;
     615         238 :         if (yych != 'l') goto yy12;
     616         238 :         yych = *++scanner->cursor;
     617         238 :         if (yych != 's') goto yy12;
     618         238 :         yych = *++scanner->cursor;
     619         238 :         if (yych != 'e') goto yy12;
     620         238 :         ++scanner->cursor;
     621         238 :         if ((yych = *scanner->cursor) <= 'Z') {
     622         236 :                 if (yych <= '/') goto yy36;
     623           1 :                 if (yych <= '9') goto yy11;
     624           1 :                 if (yych >= 'A') goto yy11;
     625             :         } else {
     626           2 :                 if (yych <= '_') {
     627           0 :                         if (yych >= '_') goto yy11;
     628             :                 } else {
     629           2 :                         if (yych <= '`') goto yy36;
     630           2 :                         if (yych <= 'z') goto yy11;
     631             :                 }
     632             :         }
     633             : yy36:
     634             : #line 429 "protobuf-c-text/parse.re"
     635             :         { t.boolean=false; RETURN(TOK_BOOLEAN); }
     636             : #line 637 "protobuf-c-text/parse.c"
     637             : yy37:
     638          67 :         yych = *++scanner->cursor;
     639          67 :         if (yych != 'u') goto yy12;
     640          67 :         yych = *++scanner->cursor;
     641          67 :         if (yych != 'e') goto yy12;
     642          67 :         ++scanner->cursor;
     643          67 :         if ((yych = *scanner->cursor) <= 'Z') {
     644          65 :                 if (yych <= '/') goto yy40;
     645           1 :                 if (yych <= '9') goto yy11;
     646           1 :                 if (yych >= 'A') goto yy11;
     647             :         } else {
     648           2 :                 if (yych <= '_') {
     649           0 :                         if (yych >= '_') goto yy11;
     650             :                 } else {
     651           2 :                         if (yych <= '`') goto yy40;
     652           2 :                         if (yych <= 'z') goto yy11;
     653             :                 }
     654             :         }
     655             : yy40:
     656             : #line 428 "protobuf-c-text/parse.re"
     657             :         { t.boolean=true; RETURN(TOK_BOOLEAN); }
     658             : #line 659 "protobuf-c-text/parse.c"
     659             : yy41:
     660         689 :         ++scanner->cursor;
     661         689 :         if (scanner->limit <= scanner->cursor) YYFILL(1);
     662         689 :         yych = *scanner->cursor;
     663         689 :         if (yych <= '/') goto yy6;
     664         122 :         if (yych <= '9') goto yy41;
     665           0 :         goto yy6;
     666             : yy43:
     667        2185 :         yyaccept = 0;
     668        2185 :         scanner->marker = ++scanner->cursor;
     669        2185 :         if ((scanner->limit - scanner->cursor) < 2) YYFILL(2);
     670        2185 :         yych = *scanner->cursor;
     671        2185 :         if (yych == '.') goto yy7;
     672        2184 :         if (yych <= '/') goto yy6;
     673        1424 :         if (yych <= '9') goto yy43;
     674           0 :         goto yy6;
     675             : }
     676             : #line 455 "protobuf-c-text/parse.re"
     677             : 
     678             : }
     679             : 
     680             : /** @} */  /* End of lexer group. */
     681             : 
     682             : /** \defgroup state Routines that define a simple finite state machine
     683             :  * \ingroup internal
     684             :  * @{
     685             :  */
     686             : 
     687             : /** StateId enumeration.
     688             :  *
     689             :  * A list of states for the FSM.
     690             :  */
     691             : typedef enum {
     692             :   STATE_OPEN,       /**< Ready to start a new statement or close
     693             :                       a nested message. */
     694             :   STATE_ASSIGNMENT, /**< Ready to assign a scalar or a nested message. */
     695             :   STATE_VALUE,      /**< Assign the scalar. */
     696             :   STATE_DONE        /**< Nothing more to read or there's been an error. */
     697             : } StateId;
     698             : 
     699             : /** Max size of an error message. */
     700             : #define STATE_ERROR_STR_MAX 160
     701             : 
     702             : /** Maintain state for the FSM.
     703             :  *
     704             :  * Tracks the current state of the FSM.
     705             :  */
     706             : typedef struct {
     707             :   Scanner *scanner;         /**< Tracks state for the scanner. */
     708             :   const ProtobufCFieldDescriptor *field;  /**< After finding a
     709             :                           \b TOK_BAREWORD in a \b STATE_OPEN \c field
     710             :                           is set to the field in the message that
     711             :                           matches that bareword. */
     712             :   int current_msg;          /**< Index on the message stack of the
     713             :                               current message. */
     714             :   int max_msg;              /**< Size of the message stack. */
     715             :   ProtobufCMessage **msgs;  /**< The message stack.  As nested messages
     716             :                               are found, they're put here. */
     717             :   ProtobufCAllocator *allocator;  /**< allocator functions. */
     718             :   int error;                /**< Notes an error has occurred. */
     719             :   char *error_str;          /**< Text of error. */
     720             : } State;
     721             : 
     722             : /** Initialise a \c State struct.
     723             :  * \param[in,out] state A state struct pointer - the is the state
     724             :  *                      for the FSM.
     725             :  * \param[in,out] scanner The state struct for the scanner.
     726             :  * \param[in] descriptor Message descriptor.
     727             :  * \param[in] allocator Allocator functions.
     728             :  * \return Success (1) or failure (0). Failure is due to out of
     729             :  *         memory errors.
     730             :  */
     731             : static int
     732             : state_init(State *state,
     733             :     Scanner *scanner,
     734             :     const ProtobufCMessageDescriptor *descriptor,
     735             :     ProtobufCAllocator *allocator)
     736             : {
     737             :   ProtobufCMessage *msg;
     738             : 
     739             :   memset(state, 0, sizeof(State));
     740             :   state->allocator = allocator;
     741             :   state->scanner = scanner;
     742             :   state->error_str = ST_ALLOC(STATE_ERROR_STR_MAX);
     743             :   state->msgs = ST_ALLOC(10 * sizeof(ProtobufCMessage *));
     744             :   state->max_msg = 10;
     745             :   msg = ST_ALLOC(descriptor->sizeof_message);
     746             :   if (!state->msgs || !msg || !state->error_str) {
     747             :     ST_FREE(state->error_str);
     748             :     ST_FREE(state->msgs);
     749             :     ST_FREE(msg);
     750             :     return 0;
     751             :   }
     752             :   descriptor->message_init(msg);
     753             :   state->msgs[0] = msg;
     754             : 
     755             :   return 1;
     756             : }
     757             : 
     758             : /** Free internal data in a \c State struct.
     759             :  *
     760             :  * Frees allocated data within the \c State instance. Note that the
     761             :  * \c State instance itself is not freed and that the \c State instance
     762             :  * contains a pointer to the \c ProtobufCAllocator allocator that
     763             :  * was passed in state_init().
     764             :  *
     765             :  * Note also that the \c error_str element is only freed if there hasn't
     766             :  * been an error.  If there has been an error, the responsibility falls
     767             :  * on the caller to free \c error_str .
     768             :  *
     769             :  * \param[in,out] state A state struct pointer.
     770             :  */
     771             : static void
     772             : state_free(State *state)
     773             : {
     774             :   if (!state->error) {
     775             :     ST_FREE(state->error_str);
     776             :   }
     777             :   ST_FREE(state->msgs);
     778             : }
     779             : 
     780             : /*
     781             :  * Helper function to handle errors.
     782             :  */
     783             : /** Handle an error in the FSM.
     784             :  *
     785             :  * At any point in the FSM if an error is encounters, call this function
     786             :  * with an explination of the error - and return the resulting value.
     787             :  *
     788             :  * \param[in,out] state A state struct pointer.
     789             :  * \param[in] t The \c Token to process.
     790             :  * \param[in] error_fmt printf style format string for the error message.
     791             :  * \param[in] ... Arguments for \c error_fmt .
     792             :  * \return This will always return \c STATE_DONE .
     793             :  */
     794             : static StateId state_error(State *state, Token *t, char *error_fmt, ...)
     795             :   __attribute__((format(printf, 3, 4)));
     796             : static StateId
     797             : state_error(State *state, Token *t, char *error_fmt, ...)
     798             : {
     799             :   va_list args;
     800             :   int error_idx;
     801             : 
     802             :   /* 10 solid lines of errors is more than enough. */
     803             :   state->error = 1;
     804             :   error_idx = snprintf(state->error_str, STATE_ERROR_STR_MAX,
     805             :       "Error found on line %d.\n", state->scanner->line);
     806             : 
     807             :   if (error_idx < STATE_ERROR_STR_MAX) {
     808             :     va_start(args, error_fmt);
     809             :     vsnprintf(state->error_str + error_idx, STATE_ERROR_STR_MAX - error_idx,
     810             :         error_fmt, args);
     811             :     va_end(args);
     812             :   }
     813             : 
     814             :   return STATE_DONE;
     815             : }
     816             : 
     817             : /** Expect an element name (bareword) or a closing brace.
     818             :  *
     819             :  * Initial state, and state after each assignment completes (or a message
     820             :  * assignment starts. If a bareword is found, go into \c STATE_ASSIGNMENT
     821             :  * and if a closing brace is found, go into \c STATE_DONE.
     822             :  *
     823             :  * If something else is found or if there are no more messages on the stack
     824             :  * (in other words, we're already at the base message), call and return
     825             :  * with state_error().
     826             :  *
     827             :  * \param[in,out] state A state struct pointer.
     828             :  * \param[in] t The \c Token to process.
     829             :  * \return A StateID value.
     830             :  */
     831             : static StateId
     832             : state_open(State *state, Token *t)
     833             : {
     834             :   switch (t->id) {
     835             :     case TOK_BAREWORD:
     836             :       state->field = protobuf_c_message_descriptor_get_field_by_name(
     837             :           state->msgs[state->current_msg]->descriptor, t->bareword);
     838             :       if (state->field) {
     839             :         if (state->field->label != PROTOBUF_C_LABEL_REQUIRED
     840             :             && state->field->label != PROTOBUF_C_LABEL_OPTIONAL
     841             :             && state->field->label != PROTOBUF_C_LABEL_REPEATED) {
     842             :           return state_error(state, t,
     843             :               "Internal error: unknown label type %d for '%s'.",
     844             :               state->field->label, state->field->name);
     845             :         }
     846             :         return STATE_ASSIGNMENT;
     847             :       } else {
     848             :         return state_error(state, t, "Can't find field '%s' in message '%s'.",
     849             :                            t->bareword,
     850             :                            state->msgs[state->current_msg]->descriptor->name);
     851             :       }
     852             :       break;
     853             :     case TOK_CBRACE:
     854             :       if (state->current_msg > 0) {
     855             :         state->current_msg--;
     856             :       } else {
     857             :         return state_error(state, t, "Extra closing brace found.");
     858             :       }
     859             :       return STATE_OPEN;
     860             :       break;
     861             :     case TOK_EOF:
     862             :       if (state->current_msg > 0) {
     863             :         return state_error(state, t, "Missing '%d' closing braces.",
     864             :             state->current_msg);
     865             :       }
     866             :       return STATE_DONE;
     867             :       break;
     868             :     default:
     869             :       return state_error(state, t,
     870             :                          "Expected element name or '}'; found '%s' instead.",
     871             :                          token2txt(t));
     872             :       break;
     873             :   }
     874             : }
     875             : 
     876             : /** Expect a colon or opening brace.
     877             :  *
     878             :  * The state where we expect an assignment.
     879             :  *
     880             :  * \param[in,out] state A state struct pointer.
     881             :  * \param[in] t The \c Token to process.
     882             :  * \return A StateID value.
     883             :  */
     884             : static StateId
     885             : state_assignment(State *state, Token *t)
     886             : {
     887             :   ProtobufCMessage *msg;
     888             : 
     889             :   msg = state->msgs[state->current_msg];
     890             :   switch (t->id) {
     891             :     case TOK_COLON:
     892             :       if (state->field->type == PROTOBUF_C_TYPE_MESSAGE) {
     893             :         return state_error(state, t,
     894             :             "Expected a '{', got a ':' - '%s' is a message type field.",
     895             :             state->field->name);
     896             :       }
     897             :       return STATE_VALUE;
     898             :       break;
     899             :     case TOK_OBRACE:
     900             :       if (state->field->type == PROTOBUF_C_TYPE_MESSAGE) {
     901             :         ProtobufCMessage **tmp;
     902             :         size_t n_members;
     903             : 
     904             :         /* Don't assign over an existing message. */
     905             :         if (state->field->label == PROTOBUF_C_LABEL_OPTIONAL
     906             :             || state->field->label == PROTOBUF_C_LABEL_REQUIRED) {
     907             :           /* Do optional member accounting. */
     908             :           if (STRUCT_MEMBER(protobuf_c_boolean, msg,
     909             :                 state->field->offset)) {
     910             :             return state_error(state, t,
     911             :                 "The '%s' message has already been assigned.",
     912             :                 state->field->name);
     913             :           }
     914             :         }
     915             : 
     916             :         /* Allocate space for the repeated message list. */
     917             :         if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
     918             :           STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
     919             :           n_members = STRUCT_MEMBER(size_t, msg,
     920             :                                     state->field->quantifier_offset);
     921             :           tmp = local_realloc(
     922             :               STRUCT_MEMBER(ProtobufCMessage *, msg, state->field->offset),
     923             :               (n_members - 1) * sizeof(ProtobufCMessage *),
     924             :               n_members * sizeof(ProtobufCMessage *),
     925             :               state->allocator);
     926             :           if (!tmp) {
     927             :             return state_error(state, t, "Malloc failure.");
     928             :           }
     929             :           STRUCT_MEMBER(ProtobufCMessage **, msg, state->field->offset)
     930             :             = tmp;
     931             :           tmp[n_members - 1] = NULL;
     932             :         }
     933             : 
     934             :         /* Create and push a new message on the message stack. */
     935             :         state->current_msg++;
     936             :         if (state->current_msg == state->max_msg) {
     937             :           ProtobufCMessage **tmp_msgs;
     938             : 
     939             :           state->max_msg += 10;
     940             :           tmp_msgs = local_realloc(
     941             :               state->msgs, (state->current_msg) * sizeof(ProtobufCMessage *),
     942             :               (state->max_msg) * sizeof(ProtobufCMessage *),
     943             :               state->allocator);
     944             :           if (!tmp_msgs) {
     945             :             return state_error(state, t, "Malloc failure.");
     946             :           }
     947             :           state->msgs = tmp_msgs;
     948             :         }
     949             :         state->msgs[state->current_msg]
     950             :           = ST_ALLOC(((ProtobufCMessageDescriptor *)
     951             :                state->field->descriptor)->sizeof_message);
     952             :         if (!state->msgs[state->current_msg]) {
     953             :           return state_error(state, t, "Malloc failure.");
     954             :         }
     955             :         ((ProtobufCMessageDescriptor *)state->field->descriptor)
     956             :           ->message_init(state->msgs[state->current_msg]);
     957             : 
     958             :         /* Assign the message just created. */
     959             :         if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
     960             :           tmp[n_members - 1] = state->msgs[state->current_msg];
     961             :           return STATE_OPEN;
     962             :         } else {
     963             :           STRUCT_MEMBER(ProtobufCMessage *, msg, state->field->offset)
     964             :             = state->msgs[state->current_msg];
     965             :           return STATE_OPEN;
     966             :         }
     967             : 
     968             :       } else {
     969             :         return state_error(state, t,
     970             :             "'%s' is not a message field.", state->field->name);
     971             :       }
     972             :       break;
     973             :     default:
     974             :       return state_error(state, t,
     975             :                          "Expected ':' or '{'; found '%s' instead.",
     976             :                          token2txt(t));
     977             :       break;
     978             :   }
     979             : }
     980             : 
     981             : /** Expect a quoted string, enum (bareword) or boolean.
     982             :  *
     983             :  * Assign the value in \c Token to the field we identified in the
     984             :  * state_open() call.  This function is huge in order to handle the
     985             :  * variety of data types and the struct offset math required to manipulate
     986             :  * them.
     987             :  *
     988             :  * \param[in,out] state A state struct pointer.
     989             :  * \param[in] t The \c Token to process.
     990             :  * \return A StateID value.
     991             :  */
     992             : static StateId
     993             : state_value(State *state, Token *t)
     994             : {
     995             :   ProtobufCMessage *msg;
     996             :   size_t n_members;
     997             :   char *end;
     998             :   int64_t val;
     999             : 
    1000             :   msg = state->msgs[state->current_msg];
    1001             :   if (state->field->type != PROTOBUF_C_TYPE_STRING) {
    1002             :     if (state->field->label == PROTOBUF_C_LABEL_OPTIONAL) {
    1003             :       /* Do optional member accounting. */
    1004             :       if (STRUCT_MEMBER(protobuf_c_boolean, msg,
    1005             :             state->field->quantifier_offset)) {
    1006             :         return state_error(state, t,
    1007             :             "'%s' has already been assigned.", state->field->name);
    1008             :       }
    1009             :       STRUCT_MEMBER(protobuf_c_boolean, msg,
    1010             :             state->field->quantifier_offset) = 1;
    1011             :     }
    1012             :   }
    1013             :   switch (t->id) {
    1014             :     case TOK_BAREWORD:
    1015             :       if (state->field->type == PROTOBUF_C_TYPE_ENUM) {
    1016             :         ProtobufCEnumDescriptor *enumd;
    1017             :         const ProtobufCEnumValue *enumv;
    1018             : 
    1019             :         enumd = (ProtobufCEnumDescriptor *)state->field->descriptor;
    1020             :         enumv = protobuf_c_enum_descriptor_get_value_by_name(enumd,
    1021             :             t->bareword);
    1022             :         if (enumv) {
    1023             :           if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1024             :             int *tmp;
    1025             : 
    1026             :             STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1027             :             n_members = STRUCT_MEMBER(size_t, msg,
    1028             :                 state->field->quantifier_offset);
    1029             :             tmp = local_realloc(
    1030             :                 STRUCT_MEMBER(int *, msg, state->field->offset),
    1031             :                 (n_members - 1) * sizeof(int),
    1032             :                 n_members * sizeof(int), state->allocator);
    1033             :             if (!tmp) {
    1034             :               return state_error(state, t, "Malloc failure.");
    1035             :             }
    1036             :             STRUCT_MEMBER(int *, msg, state->field->offset) = tmp;
    1037             :             tmp[n_members - 1] = enumv->value;
    1038             :             return STATE_OPEN;
    1039             :           } else {
    1040             :             STRUCT_MEMBER(int, msg, state->field->offset) = enumv->value;
    1041             :             return STATE_OPEN;
    1042             :           }
    1043             :         } else {
    1044             :           return state_error(state, t,
    1045             :               "Invalid enum '%s' for field '%s'.",
    1046             :               t->bareword, state->field->name);
    1047             :         }
    1048             :       }
    1049             :       return state_error(state, t,
    1050             :           "'%s' is not an enum field.", state->field->name);
    1051             :       break;
    1052             : 
    1053             :     case TOK_BOOLEAN:
    1054             :       if (state->field->type == PROTOBUF_C_TYPE_BOOL) {
    1055             :         if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1056             :           protobuf_c_boolean *tmp;
    1057             : 
    1058             :           STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1059             :           n_members = STRUCT_MEMBER(size_t, msg,
    1060             :                                     state->field->quantifier_offset);
    1061             :           tmp = local_realloc(
    1062             :               STRUCT_MEMBER(protobuf_c_boolean *, msg, state->field->offset),
    1063             :               (n_members - 1) * sizeof(protobuf_c_boolean),
    1064             :               n_members * sizeof(protobuf_c_boolean), state->allocator);
    1065             :           if (!tmp) {
    1066             :             return state_error(state, t, "Malloc failure.");
    1067             :           }
    1068             :           STRUCT_MEMBER(protobuf_c_boolean *, msg, state->field->offset) = tmp;
    1069             :           tmp[n_members - 1] = t->boolean;
    1070             :           return STATE_OPEN;
    1071             :         } else {
    1072             :           STRUCT_MEMBER(protobuf_c_boolean, msg, state->field->offset)
    1073             :             = t->boolean;
    1074             :           return STATE_OPEN;
    1075             :         }
    1076             : 
    1077             :       }
    1078             :       return state_error(state, t,
    1079             :           "'%s' is not a boolean field.", state->field->name);
    1080             :       break;
    1081             : 
    1082             :     case TOK_QUOTED:
    1083             :       if (state->field->type == PROTOBUF_C_TYPE_BYTES) {
    1084             :         ProtobufCBinaryData *pbbd;
    1085             : 
    1086             :         if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1087             :           STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1088             :           n_members = STRUCT_MEMBER(size_t, msg,
    1089             :                                     state->field->quantifier_offset);
    1090             :           pbbd = local_realloc(
    1091             :               STRUCT_MEMBER(ProtobufCBinaryData *, msg, state->field->offset),
    1092             :               (n_members - 1) * sizeof(ProtobufCBinaryData),
    1093             :               n_members * sizeof(ProtobufCBinaryData), state->allocator);
    1094             :           if (!pbbd) {
    1095             :             return state_error(state, t, "Malloc failure.");
    1096             :           }
    1097             :           STRUCT_MEMBER(ProtobufCBinaryData *, msg, state->field->offset)
    1098             :             = pbbd;
    1099             :           pbbd[n_members - 1].data = ST_ALLOC(t->qs->len);
    1100             :           if (!pbbd[n_members - 1].data) {
    1101             :             return state_error(state, t, "Malloc failure.");
    1102             :           }
    1103             :           memcpy(pbbd[n_members - 1].data, t->qs->data, t->qs->len);
    1104             :           pbbd[n_members - 1].len = t->qs->len;
    1105             :           return STATE_OPEN;
    1106             :         } else {
    1107             :           pbbd = STRUCT_MEMBER_PTR(ProtobufCBinaryData, msg,
    1108             :               state->field->offset);
    1109             :           pbbd->data = ST_ALLOC(t->qs->len);
    1110             :           if (!pbbd->data) {
    1111             :             return state_error(state, t, "Malloc failure.");
    1112             :           }
    1113             :           memcpy(pbbd->data, t->qs->data, t->qs->len);
    1114             :           pbbd->len = t->qs->len;
    1115             :           return STATE_OPEN;
    1116             :         }
    1117             : 
    1118             :       } else if (state->field->type == PROTOBUF_C_TYPE_STRING) {
    1119             :         if (state->field->label == PROTOBUF_C_LABEL_OPTIONAL) {
    1120             :           /* Do optional member accounting. */
    1121             :           if (STRUCT_MEMBER(unsigned char *, msg, state->field->offset)
    1122             :               && (STRUCT_MEMBER(unsigned char *, msg, state->field->offset)
    1123             :                 != state->field->default_value)) {
    1124             :             return state_error(state, t,
    1125             :                 "'%s' has already been assigned.", state->field->name);
    1126             :           }
    1127             :         }
    1128             :         if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1129             :           unsigned char **s;
    1130             : 
    1131             :           STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1132             :           n_members = STRUCT_MEMBER(size_t, msg,
    1133             :                                     state->field->quantifier_offset);
    1134             :           s = local_realloc(
    1135             :               STRUCT_MEMBER(unsigned char **, msg, state->field->offset),
    1136             :               (n_members - 1) * sizeof(unsigned char *),
    1137             :               n_members * sizeof(unsigned char *), state->allocator);
    1138             :           if (!s) {
    1139             :             return state_error(state, t, "Malloc failure.");
    1140             :           }
    1141             :           STRUCT_MEMBER(unsigned char **, msg, state->field->offset) = s;
    1142             :           s[n_members - 1] = ST_ALLOC(t->qs->len + 1);
    1143             :           if (!s[n_members - 1]) {
    1144             :             return state_error(state, t, "Malloc failure.");
    1145             :           }
    1146             :           memcpy(s[n_members - 1], t->qs->data, t->qs->len);
    1147             :           s[n_members - 1][t->qs->len] = '\0';
    1148             :           return STATE_OPEN;
    1149             :         } else {
    1150             :           unsigned char *s;
    1151             : 
    1152             :           s = ST_ALLOC(t->qs->len + 1);
    1153             :           if (!s) {
    1154             :             return state_error(state, t, "Malloc failure.");
    1155             :           }
    1156             :           memcpy(s, t->qs->data, t->qs->len);
    1157             :           s[t->qs->len] = '\0';
    1158             :           STRUCT_MEMBER(unsigned char *, msg, state->field->offset) = s;
    1159             :           return STATE_OPEN;
    1160             :         }
    1161             : 
    1162             :       }
    1163             :       return state_error(state, t,
    1164             :           "'%s' is not a string or byte field.", state->field->name);
    1165             :       break;
    1166             : 
    1167             :     case TOK_NUMBER:
    1168             :       switch (state->field->type) {
    1169             :         case PROTOBUF_C_TYPE_INT32:
    1170             :         case PROTOBUF_C_TYPE_UINT32:
    1171             :         case PROTOBUF_C_TYPE_FIXED32:
    1172             :           val = strtoul(t->number, &end, 10);
    1173             :           if (*end != '\0' || val > (uint64_t)UINT32_MAX) {
    1174             :             return state_error(state, t,
    1175             :                 "Unable to convert '%s' for field '%s'.",
    1176             :                 t->number, state->field->name);
    1177             :           }
    1178             :           if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1179             :             uint32_t *vals;
    1180             : 
    1181             :             STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1182             :             n_members = STRUCT_MEMBER(size_t, msg,
    1183             :                                       state->field->quantifier_offset);
    1184             :             vals = local_realloc(
    1185             :                 STRUCT_MEMBER(uint32_t *, msg, state->field->offset),
    1186             :                 (n_members - 1) * sizeof(uint32_t),
    1187             :                 n_members * sizeof(uint32_t), state->allocator);
    1188             :             if (!vals) {
    1189             :               return state_error(state, t, "Malloc failure.");
    1190             :             }
    1191             :             STRUCT_MEMBER(uint32_t *, msg, state->field->offset) = vals;
    1192             :             vals[n_members - 1] = (uint32_t)val;
    1193             :             return STATE_OPEN;
    1194             :           } else {
    1195             :             STRUCT_MEMBER(uint32_t, msg, state->field->offset) = (uint32_t)val;
    1196             :             return STATE_OPEN;
    1197             :           }
    1198             :           break;
    1199             : 
    1200             :         case PROTOBUF_C_TYPE_SINT32:
    1201             :         case PROTOBUF_C_TYPE_SFIXED32:
    1202             :           val = strtol(t->number, &end, 10);
    1203             :           if (*end != '\0' || val < INT32_MIN || val > INT32_MAX) {
    1204             :             return state_error(state, t,
    1205             :                 "Unable to convert '%s' for field '%s'.",
    1206             :                 t->number, state->field->name);
    1207             :           }
    1208             :           if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1209             :             int32_t *vals;
    1210             : 
    1211             :             STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1212             :             n_members = STRUCT_MEMBER(size_t, msg,
    1213             :                                       state->field->quantifier_offset);
    1214             :             vals = local_realloc(
    1215             :                 STRUCT_MEMBER(int32_t *, msg, state->field->offset),
    1216             :                 (n_members - 1) * sizeof(int32_t),
    1217             :                 n_members * sizeof(int32_t), state->allocator);
    1218             :             if (!vals) {
    1219             :               return state_error(state, t, "Malloc failure.");
    1220             :             }
    1221             :             STRUCT_MEMBER(int32_t *, msg, state->field->offset) = vals;
    1222             :             vals[n_members - 1] = (uint32_t)val;
    1223             :             return STATE_OPEN;
    1224             :           } else {
    1225             :             STRUCT_MEMBER(int32_t, msg, state->field->offset) = val;
    1226             :             return STATE_OPEN;
    1227             :           }
    1228             :           break;
    1229             : 
    1230             :         case PROTOBUF_C_TYPE_INT64:
    1231             :         case PROTOBUF_C_TYPE_UINT64:
    1232             :         case PROTOBUF_C_TYPE_FIXED64:
    1233             :           val = strtoull(t->number, &end, 10);
    1234             :           if (*end != '\0') {
    1235             :             return state_error(state, t,
    1236             :                 "Unable to convert '%s' for field '%s'.",
    1237             :                 t->number, state->field->name);
    1238             :           }
    1239             :           if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1240             :             uint64_t *vals;
    1241             : 
    1242             :             STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1243             :             n_members = STRUCT_MEMBER(size_t, msg,
    1244             :                                       state->field->quantifier_offset);
    1245             :             vals = local_realloc(
    1246             :                 STRUCT_MEMBER(uint64_t *, msg, state->field->offset),
    1247             :                 (n_members - 1) * sizeof(uint64_t),
    1248             :                 n_members * sizeof(uint64_t), state->allocator);
    1249             :             if (!vals) {
    1250             :               return state_error(state, t, "Malloc failure.");
    1251             :             }
    1252             :             STRUCT_MEMBER(uint64_t *, msg, state->field->offset) = vals;
    1253             :             vals[n_members - 1] = val;
    1254             :             return STATE_OPEN;
    1255             :           } else {
    1256             :             STRUCT_MEMBER(uint64_t, msg, state->field->offset) = val;
    1257             :             return STATE_OPEN;
    1258             :           }
    1259             :           break;
    1260             : 
    1261             :         case PROTOBUF_C_TYPE_SINT64:
    1262             :         case PROTOBUF_C_TYPE_SFIXED64:
    1263             :           val = strtoll(t->number, &end, 10);
    1264             :           if (*end != '\0') {
    1265             :             return state_error(state, t,
    1266             :                 "Unable to convert '%s' for field '%s'.",
    1267             :                 t->number, state->field->name);
    1268             :           }
    1269             :           if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1270             :             int64_t *vals;
    1271             : 
    1272             :             STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1273             :             n_members = STRUCT_MEMBER(size_t, msg,
    1274             :                                       state->field->quantifier_offset);
    1275             :             vals = local_realloc(
    1276             :                 STRUCT_MEMBER(int64_t *, msg, state->field->offset),
    1277             :                 (n_members - 1) * sizeof(int64_t),
    1278             :                 n_members * sizeof(int64_t), state->allocator);
    1279             :             if (!vals) {
    1280             :               return state_error(state, t, "Malloc failure.");
    1281             :             }
    1282             :             STRUCT_MEMBER(int64_t *, msg, state->field->offset) = vals;
    1283             :             vals[n_members - 1] = val;
    1284             :             return STATE_OPEN;
    1285             :           } else {
    1286             :             STRUCT_MEMBER(int64_t, msg, state->field->offset) = val;
    1287             :             return STATE_OPEN;
    1288             :           }
    1289             :           break;
    1290             : 
    1291             :         case PROTOBUF_C_TYPE_FLOAT:
    1292             :           {
    1293             :             float val, *vals;
    1294             : 
    1295             :             errno = 0;
    1296             :             val = strtof(t->number, &end);
    1297             :             if (*end != '\0' || errno == ERANGE) {
    1298             :               return state_error(state, t,
    1299             :                   "Unable to convert '%s' for field '%s'.",
    1300             :                   t->number, state->field->name);
    1301             :             }
    1302             :             if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1303             :               STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1304             :               n_members = STRUCT_MEMBER(size_t, msg,
    1305             :                                         state->field->quantifier_offset);
    1306             :               vals = local_realloc(
    1307             :                   STRUCT_MEMBER(float *, msg, state->field->offset),
    1308             :                   (n_members - 1) * sizeof(float),
    1309             :                   n_members * sizeof(float), state->allocator);
    1310             :               if (!vals) {
    1311             :                 return state_error(state, t, "Malloc failure.");
    1312             :               }
    1313             :               STRUCT_MEMBER(float *, msg, state->field->offset) = vals;
    1314             :               vals[n_members - 1] = val;
    1315             :               return STATE_OPEN;
    1316             :             } else {
    1317             :               STRUCT_MEMBER(float, msg, state->field->offset) = val;
    1318             :               return STATE_OPEN;
    1319             :             }
    1320             :           }
    1321             :           break;
    1322             : 
    1323             :         case PROTOBUF_C_TYPE_DOUBLE:
    1324             :           {
    1325             :             double val,*vals;
    1326             : 
    1327             :             errno = 0;
    1328             :             val = strtod(t->number, &end);
    1329             :             if (*end != '\0' || errno == ERANGE) {
    1330             :               return state_error(state, t,
    1331             :                   "Unable to convert '%s' for field '%s'.",
    1332             :                   t->number, state->field->name);
    1333             :             }
    1334             :             if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
    1335             :               STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
    1336             :               n_members = STRUCT_MEMBER(size_t, msg,
    1337             :                                         state->field->quantifier_offset);
    1338             :               vals = local_realloc(
    1339             :                   STRUCT_MEMBER(double *, msg, state->field->offset),
    1340             :                   (n_members - 1) * sizeof(double),
    1341             :                   n_members * sizeof(double), state->allocator);
    1342             :               if (!vals) {
    1343             :                 return state_error(state, t, "Malloc failure.");
    1344             :               }
    1345             :               STRUCT_MEMBER(double *, msg, state->field->offset) = vals;
    1346             :               vals[n_members - 1] = val;
    1347             :               return STATE_OPEN;
    1348             :             } else {
    1349             :               STRUCT_MEMBER(double, msg, state->field->offset) = val;
    1350             :               return STATE_OPEN;
    1351             :             }
    1352             :           }
    1353             :           break;
    1354             : 
    1355             :         default:
    1356             :           return state_error(state, t,
    1357             :               "'%s' is not a numeric field.", state->field->name);
    1358             :           break;
    1359             :       }
    1360             :       break;
    1361             : 
    1362             :     default:
    1363             :       return state_error(state, t,
    1364             :                          "Expected value; found '%s' instead.",
    1365             :                          token2txt(t));
    1366             :       break;
    1367             :   }
    1368             : }
    1369             : 
    1370             : /** Table of states and actions.
    1371             :  *
    1372             :  * This is a table of each state and the action to take when in it.
    1373             :  */
    1374             : static StateId(* states[])(State *, Token *) = {
    1375             :   [STATE_OPEN] = state_open,
    1376             :   [STATE_ASSIGNMENT] = state_assignment,
    1377             :   [STATE_VALUE] = state_value
    1378             : };
    1379             : 
    1380             : /** @} */  /* End of state group. */
    1381             : 
    1382             : /** \defgroup base-parse Base parsing function
    1383             :  * \ingroup internal
    1384             :  * @{
    1385             :  */
    1386             : 
    1387             : /** Base function for the API functions.
    1388             :  *
    1389             :  * The API functions take a string or a \c FILE.  This function takes an
    1390             :  * appropriately initialised \c Scanner instead.  After that it works
    1391             :  * the same as the protobuf_c_text_from* family of functions.
    1392             :  *
    1393             :  * \param[in] descriptor a \c ProtobufCMessageDescriptor of a message you
    1394             :  *                       want to deserialise.
    1395             :  * \param[in] scanner A \c Scanner which will be used by the FSM to parse
    1396             :  *                    the text format protobuf.
    1397             :  * \param[in,out] result A \c ProtobufCTextError instance to record any
    1398             :  *                       errors.  It is not an option to pass \c NULL for
    1399             :  *                       this and it must be checked for errors.
    1400             :  * \param[in] allocator Allocator functions.
    1401             :  * \return \c NULL on error. A \c ProtobufCMessage representation of the
    1402             :  *         text format protobuf on success.
    1403             :  */
    1404             : static ProtobufCMessage *
    1405             : protobuf_c_text_parse(const ProtobufCMessageDescriptor *descriptor,
    1406             :     Scanner *scanner,
    1407             :     ProtobufCTextError *result,
    1408             :     ProtobufCAllocator *allocator)
    1409             : {
    1410             :   Token token;
    1411             :   State state;
    1412             :   StateId state_id;
    1413             :   ProtobufCMessage *msg = NULL;
    1414             : 
    1415             :   result->error_txt = NULL;
    1416             :   result->complete = -1;  /* -1 means the check wasn't performed. */
    1417             : 
    1418             :   state_id = STATE_OPEN;
    1419             :   if (!state_init(&state, scanner, descriptor, allocator)) {
    1420             :     return NULL;
    1421             :   }
    1422             : 
    1423             :   while (state_id != STATE_DONE) {
    1424             :     token = scan(scanner, allocator);
    1425             :     if (token.id == TOK_MALLOC_ERR) {
    1426             :       token_free(&token, allocator);
    1427             :       state_error(&state, &token, "String unescape or malloc failure.");
    1428             :       break;
    1429             :     }
    1430             :     state_id = states[state_id](&state, &token);
    1431             :     token_free(&token, allocator);
    1432             :   }
    1433             : 
    1434             :   scanner_free(scanner, allocator);
    1435             :   if (state.error) {
    1436             :     result->error_txt = state.error_str;
    1437             :     if (msg) {
    1438             :       protobuf_c_message_free_unpacked(state.msgs[0], allocator);
    1439             :     }
    1440             :   } else {
    1441             :     msg = state.msgs[0];
    1442             : #ifdef HAVE_PROTOBUF_C_MESSAGE_CHECK
    1443             :     result->complete = protobuf_c_message_check(msg);
    1444             : #endif
    1445             :   }
    1446             :   state_free(&state);
    1447             :   return msg;
    1448             : }
    1449             : 
    1450             : /** @} */  /* End of base-parse group. */
    1451             : 
    1452             : /* See .h file for API docs. */
    1453             : 
    1454             : ProtobufCMessage *
    1455             : protobuf_c_text_from_file(const ProtobufCMessageDescriptor *descriptor,
    1456             :     FILE *msg_file,
    1457             :     ProtobufCTextError *result,
    1458             :     ProtobufCAllocator *allocator)
    1459             : {
    1460             :   Scanner scanner;
    1461             : 
    1462             :   scanner_init_file(&scanner, msg_file);
    1463             :   return protobuf_c_text_parse(descriptor, &scanner, result, allocator);
    1464             : }
    1465             : 
    1466             : ProtobufCMessage *
    1467             : protobuf_c_text_from_string(const ProtobufCMessageDescriptor *descriptor,
    1468             :     char *msg,
    1469             :     ProtobufCTextError *result,
    1470             :     ProtobufCAllocator *allocator)
    1471             : {
    1472             :   Scanner scanner;
    1473             : 
    1474             :   scanner_init_string(&scanner, msg);
    1475             :   return protobuf_c_text_parse(descriptor, &scanner, result, allocator);
    1476             : }

Generated by: LCOV version 1.10