protobuf-c-text
Library to generate & parse text format protobufs in C.
 All Data Structures Files Functions Variables Enumerations Enumerator Macros Groups
parse.re
Go to the documentation of this file.
1 /* c-basic-offset: 2; tab-width: 8; indent-tabs-mode: nil; mode: c
2  * vi: set shiftwidth=2 tabstop=8 expandtab filetype=c:
3  * :indentSize=2:tabSize=8:noTabs=true:mode=c:
4  */
5 
24 #include <errno.h>
25 #include <stdarg.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <protobuf-c/protobuf-c.h>
33 #include "protobuf-c-text.h"
34 #include "protobuf-c-util.h"
35 #include "config.h"
36 
55 static void *
56 local_realloc(void *ptr,
57  size_t old_size,
58  size_t size,
59  ProtobufCAllocator *allocator)
60 {
61  void *tmp;
62 
63  tmp = PBC_ALLOC(size);
64  if (!tmp) {
65  return NULL;
66  }
67  if (old_size < size) {
68  /* Extending. */
69  memcpy(tmp, ptr, old_size);
70  } else {
71  /* Truncating. */
72  memcpy(tmp, ptr, size);
73  }
74 
75  PBC_FREE(ptr);
76  return tmp;
77 }
78  /* End of utility group. */
80 
91 typedef enum {
101 } TokenId;
102 
108 typedef struct _Token {
110  union {
111  char *number;
112  char *bareword;
113  ProtobufCBinaryData *qs;
115  bool boolean;
116  };
117 } Token;
118 
127 static const char *
129 {
130  switch (t->id) {
131  case TOK_EOF:
132  return "[EOF]"; break;
133  case TOK_BAREWORD:
134  return t->bareword; break;
135  case TOK_OBRACE:
136  return "{"; break;
137  case TOK_CBRACE:
138  return "}"; break;
139  case TOK_COLON:
140  return ":"; break;
141  case TOK_QUOTED:
142  return "[string]"; break;
143  case TOK_NUMBER:
144  return t->number; break;
145  case TOK_BOOLEAN:
146  return t->boolean? "true": "false"; break;
147  default:
148  return "[UNKNOWN]"; break;
149  }
150 }
151 
160 static void
161 token_free(Token *t, ProtobufCAllocator *allocator)
162 {
163  switch (t->id) {
164  case TOK_BAREWORD:
165  PBC_FREE(t->bareword);
166  break;
167  case TOK_QUOTED:
168  PBC_FREE(t->qs->data);
169  break;
170  case TOK_NUMBER:
171  PBC_FREE(t->number);
172  break;
173  default:
174  break;
175  }
176 }
177 
182 typedef struct _Scanner {
183  unsigned char *cursor;
184  unsigned char *marker;
185  unsigned char *buffer;
186  unsigned char *limit;
187  unsigned char *token;
188  FILE *f;
190  int line;
192 } Scanner;
193 
201 static void
202 scanner_init_file(Scanner *scanner, FILE *f)
203 {
204  memset(scanner, 0, sizeof(Scanner));
205  scanner->f = f;
206  scanner->line = 1;
207 }
208 
216 static void
217 scanner_init_string(Scanner *scanner, char *buf)
218 {
219  memset(scanner, 0, sizeof(Scanner));
220  scanner->buffer = buf;
221  scanner->marker = buf;
222  scanner->cursor = buf;
223  scanner->limit = &buf[strlen(buf)];
224  scanner->line = 1;
225 }
226 
232 static void
233 scanner_free(Scanner *scanner, ProtobufCAllocator *allocator)
234 {
235  if (scanner->f && scanner->buffer)
236  PBC_FREE(scanner->buffer);
237  scanner->buffer = NULL;
238 }
239 
252 static ProtobufCBinaryData *
253 unesc_str(unsigned char *src, int len, ProtobufCAllocator *allocator)
254 {
255  ProtobufCBinaryData *dst_pbbd;
256  unsigned char *dst;
257  int i = 0, dst_len = 0;
258  unsigned char oct[4];
259 
260  dst_pbbd = PBC_ALLOC(sizeof(ProtobufCBinaryData));
261  dst = PBC_ALLOC(len + 1);
262  if (!dst_pbbd || !dst) {
263  goto unesc_str_error;
264  }
265  oct[3] = '\0';
266 
267  while (i < len) {
268  if (src[i] != '\\') {
269  dst[dst_len++] = src[i++];
270  } else {
271  i++;
272  if (i == len) {
273  /* Fell off the end of the string after \. */
274  goto unesc_str_error;
275  }
276  switch (src[i]) {
277  case '0':
278  if (i + 2 < len
279  && (src[i+1] >= '0' && src[i+1] <= '7')
280  && (src[i+2] >= '0' && src[i+2] <= '7')) {
281  memcpy(oct, src + i, 3);
282  dst[dst_len++] = (unsigned char)strtoul(oct, NULL, 8);
283  i += 2; /* Gets incremented again down below. */
284  } else {
285  /* Decoding a \0 failed or was cut off.. */
286  goto unesc_str_error;
287  }
288  break;
289  case '\'':
290  dst[dst_len++] = '\'';
291  break;
292  case '\"':
293  dst[dst_len++] = '\"';
294  break;
295  case '\\':
296  dst[dst_len++] = '\\';
297  break;
298  case 'n':
299  dst[dst_len++] = '\n';
300  break;
301  case 'r':
302  dst[dst_len++] = '\r';
303  break;
304  case 't':
305  dst[dst_len++] = '\t';
306  break;
307  default:
308  goto unesc_str_error;
309  break;
310  }
311  i++;
312  }
313  }
314 
315  dst_pbbd->data = dst;
316  dst_pbbd->len = dst_len;
317  return dst_pbbd;
318 
319 unesc_str_error:
320  PBC_FREE(dst);
321  PBC_FREE(dst_pbbd);
322  return NULL;
323 }
324 
326 #define CHUNK 4096
327 
341 static int
342 fill(Scanner *scanner, ProtobufCAllocator *allocator)
343 {
344  char *buf;
345  int len, oldlen, nmemb;
346 
347  if (scanner->token > scanner->limit) {
348  /* this shouldn't happen */
349  return 0;
350  }
351  if (scanner->f && !feof(scanner->f)) {
352  oldlen = scanner->limit - scanner->token;
353  len = CHUNK + oldlen;
354  buf = PBC_ALLOC(len);
355  if (!buf) {
356  return -1;
357  }
358  memcpy(buf, scanner->token, oldlen);
359  nmemb = fread(buf + oldlen, 1, CHUNK, scanner->f);
360  if (nmemb != CHUNK) {
361  /* Short read. eof. Append nul. */
362  len = oldlen + nmemb;
363  buf[len] = '\0';
364  }
365  /* Reset the world to use buf. */
366  scanner->cursor = &buf[scanner->cursor - scanner->token];
367  scanner->limit = buf + len;
368  scanner->token = buf;
369  PBC_FREE(scanner->buffer);
370  scanner->buffer = buf;
371  scanner->marker = buf;
372  }
373 
374  return scanner->limit >= scanner->cursor? 1: 0;
375 }
376 
378 #define RETURN(tt) { t.id = tt; return t; }
379 
380 #define YYFILL(n) { fill_result = fill(scanner, allocator); \
381  if (fill_result <= 0) \
382  RETURN((fill_result == -1? TOK_MALLOC_ERR: TOK_EOF)); }
383 
392 static Token
393 scan(Scanner *scanner, ProtobufCAllocator *allocator)
394 {
395  Token t;
396  int fill_result;
397 
398 token_start:
399  scanner->token = scanner->cursor;
400 
401  /* I don't think multiline strings are allowed. If I'm wrong,
402  * the QS re should be ["] (EQ|[^"]|NL)* ["]; */
403 
456 }
457  /* End of lexer group. */
459 
469 typedef enum {
475 } StateId;
476 
478 #define STATE_ERROR_STR_MAX 160
479 
484 typedef struct {
486  const ProtobufCFieldDescriptor *field;
492  int max_msg;
493  ProtobufCMessage **msgs;
495  ProtobufCAllocator *allocator;
496  int error;
497  char *error_str;
498 } State;
499 
509 static int
511  Scanner *scanner,
512  const ProtobufCMessageDescriptor *descriptor,
513  ProtobufCAllocator *allocator)
514 {
515  ProtobufCMessage *msg;
516 
517  memset(state, 0, sizeof(State));
518  state->allocator = allocator;
519  state->scanner = scanner;
521  state->msgs = ST_ALLOC(10 * sizeof(ProtobufCMessage *));
522  state->max_msg = 10;
523  msg = ST_ALLOC(descriptor->sizeof_message);
524  if (!state->msgs || !msg || !state->error_str) {
525  ST_FREE(state->error_str);
526  ST_FREE(state->msgs);
527  ST_FREE(msg);
528  return 0;
529  }
530  descriptor->message_init(msg);
531  state->msgs[0] = msg;
532 
533  return 1;
534 }
535 
549 static void
551 {
552  if (!state->error) {
553  ST_FREE(state->error_str);
554  }
555  ST_FREE(state->msgs);
556 }
557 
558 /*
559  * Helper function to handle errors.
560  */
572 static StateId state_error(State *state, Token *t, char *error_fmt, ...)
573  __attribute__((format(printf, 3, 4)));
574 static StateId
575 state_error(State *state, Token *t, char *error_fmt, ...)
576 {
577  va_list args;
578  int error_idx;
579 
580  /* 10 solid lines of errors is more than enough. */
581  state->error = 1;
582  error_idx = snprintf(state->error_str, STATE_ERROR_STR_MAX,
583  "Error found on line %d.\n", state->scanner->line);
584 
585  if (error_idx < STATE_ERROR_STR_MAX) {
586  va_start(args, error_fmt);
587  vsnprintf(state->error_str + error_idx, STATE_ERROR_STR_MAX - error_idx,
588  error_fmt, args);
589  va_end(args);
590  }
591 
592  return STATE_DONE;
593 }
594 
609 static StateId
610 state_open(State *state, Token *t)
611 {
612  switch (t->id) {
613  case TOK_BAREWORD:
614  state->field = protobuf_c_message_descriptor_get_field_by_name(
615  state->msgs[state->current_msg]->descriptor, t->bareword);
616  if (state->field) {
617  if (state->field->label != PROTOBUF_C_LABEL_REQUIRED
618  && state->field->label != PROTOBUF_C_LABEL_OPTIONAL
619  && state->field->label != PROTOBUF_C_LABEL_REPEATED) {
620  return state_error(state, t,
621  "Internal error: unknown label type %d for '%s'.",
622  state->field->label, state->field->name);
623  }
624  return STATE_ASSIGNMENT;
625  } else {
626  return state_error(state, t, "Can't find field '%s' in message '%s'.",
627  t->bareword,
628  state->msgs[state->current_msg]->descriptor->name);
629  }
630  break;
631  case TOK_CBRACE:
632  if (state->current_msg > 0) {
633  state->current_msg--;
634  } else {
635  return state_error(state, t, "Extra closing brace found.");
636  }
637  return STATE_OPEN;
638  break;
639  case TOK_EOF:
640  if (state->current_msg > 0) {
641  return state_error(state, t, "Missing '%d' closing braces.",
642  state->current_msg);
643  }
644  return STATE_DONE;
645  break;
646  default:
647  return state_error(state, t,
648  "Expected element name or '}'; found '%s' instead.",
649  token2txt(t));
650  break;
651  }
652 }
653 
662 static StateId
664 {
665  ProtobufCMessage *msg;
666 
667  msg = state->msgs[state->current_msg];
668  switch (t->id) {
669  case TOK_COLON:
670  if (state->field->type == PROTOBUF_C_TYPE_MESSAGE) {
671  return state_error(state, t,
672  "Expected a '{', got a ':' - '%s' is a message type field.",
673  state->field->name);
674  }
675  return STATE_VALUE;
676  break;
677  case TOK_OBRACE:
678  if (state->field->type == PROTOBUF_C_TYPE_MESSAGE) {
679  ProtobufCMessage **tmp;
680  size_t n_members;
681 
682  /* Don't assign over an existing message. */
683  if (state->field->label == PROTOBUF_C_LABEL_OPTIONAL
684  || state->field->label == PROTOBUF_C_LABEL_REQUIRED) {
685  /* Do optional member accounting. */
686  if (STRUCT_MEMBER(protobuf_c_boolean, msg,
687  state->field->offset)) {
688  return state_error(state, t,
689  "The '%s' message has already been assigned.",
690  state->field->name);
691  }
692  }
693 
694  /* Allocate space for the repeated message list. */
695  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
696  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
697  n_members = STRUCT_MEMBER(size_t, msg,
698  state->field->quantifier_offset);
699  tmp = local_realloc(
700  STRUCT_MEMBER(ProtobufCMessage *, msg, state->field->offset),
701  (n_members - 1) * sizeof(ProtobufCMessage *),
702  n_members * sizeof(ProtobufCMessage *),
703  state->allocator);
704  if (!tmp) {
705  return state_error(state, t, "Malloc failure.");
706  }
707  STRUCT_MEMBER(ProtobufCMessage **, msg, state->field->offset)
708  = tmp;
709  tmp[n_members - 1] = NULL;
710  }
711 
712  /* Create and push a new message on the message stack. */
713  state->current_msg++;
714  if (state->current_msg == state->max_msg) {
715  ProtobufCMessage **tmp_msgs;
716 
717  state->max_msg += 10;
718  tmp_msgs = local_realloc(
719  state->msgs, (state->current_msg) * sizeof(ProtobufCMessage *),
720  (state->max_msg) * sizeof(ProtobufCMessage *),
721  state->allocator);
722  if (!tmp_msgs) {
723  return state_error(state, t, "Malloc failure.");
724  }
725  state->msgs = tmp_msgs;
726  }
727  state->msgs[state->current_msg]
728  = ST_ALLOC(((ProtobufCMessageDescriptor *)
729  state->field->descriptor)->sizeof_message);
730  if (!state->msgs[state->current_msg]) {
731  return state_error(state, t, "Malloc failure.");
732  }
733  ((ProtobufCMessageDescriptor *)state->field->descriptor)
734  ->message_init(state->msgs[state->current_msg]);
735 
736  /* Assign the message just created. */
737  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
738  tmp[n_members - 1] = state->msgs[state->current_msg];
739  return STATE_OPEN;
740  } else {
741  STRUCT_MEMBER(ProtobufCMessage *, msg, state->field->offset)
742  = state->msgs[state->current_msg];
743  return STATE_OPEN;
744  }
745 
746  } else {
747  return state_error(state, t,
748  "'%s' is not a message field.", state->field->name);
749  }
750  break;
751  default:
752  return state_error(state, t,
753  "Expected ':' or '{'; found '%s' instead.",
754  token2txt(t));
755  break;
756  }
757 }
758 
770 static StateId
772 {
773  ProtobufCMessage *msg;
774  size_t n_members;
775  char *end;
776  int64_t val;
777 
778  msg = state->msgs[state->current_msg];
779  if (state->field->type != PROTOBUF_C_TYPE_STRING) {
780  if (state->field->label == PROTOBUF_C_LABEL_OPTIONAL) {
781  /* Do optional member accounting. */
782  if (STRUCT_MEMBER(protobuf_c_boolean, msg,
783  state->field->quantifier_offset)) {
784  return state_error(state, t,
785  "'%s' has already been assigned.", state->field->name);
786  }
787  STRUCT_MEMBER(protobuf_c_boolean, msg,
788  state->field->quantifier_offset) = 1;
789  }
790  }
791  switch (t->id) {
792  case TOK_BAREWORD:
793  if (state->field->type == PROTOBUF_C_TYPE_ENUM) {
794  ProtobufCEnumDescriptor *enumd;
795  const ProtobufCEnumValue *enumv;
796 
797  enumd = (ProtobufCEnumDescriptor *)state->field->descriptor;
798  enumv = protobuf_c_enum_descriptor_get_value_by_name(enumd,
799  t->bareword);
800  if (enumv) {
801  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
802  int *tmp;
803 
804  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
805  n_members = STRUCT_MEMBER(size_t, msg,
806  state->field->quantifier_offset);
807  tmp = local_realloc(
808  STRUCT_MEMBER(int *, msg, state->field->offset),
809  (n_members - 1) * sizeof(int),
810  n_members * sizeof(int), state->allocator);
811  if (!tmp) {
812  return state_error(state, t, "Malloc failure.");
813  }
814  STRUCT_MEMBER(int *, msg, state->field->offset) = tmp;
815  tmp[n_members - 1] = enumv->value;
816  return STATE_OPEN;
817  } else {
818  STRUCT_MEMBER(int, msg, state->field->offset) = enumv->value;
819  return STATE_OPEN;
820  }
821  } else {
822  return state_error(state, t,
823  "Invalid enum '%s' for field '%s'.",
824  t->bareword, state->field->name);
825  }
826  }
827  return state_error(state, t,
828  "'%s' is not an enum field.", state->field->name);
829  break;
830 
831  case TOK_BOOLEAN:
832  if (state->field->type == PROTOBUF_C_TYPE_BOOL) {
833  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
834  protobuf_c_boolean *tmp;
835 
836  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
837  n_members = STRUCT_MEMBER(size_t, msg,
838  state->field->quantifier_offset);
839  tmp = local_realloc(
840  STRUCT_MEMBER(protobuf_c_boolean *, msg, state->field->offset),
841  (n_members - 1) * sizeof(protobuf_c_boolean),
842  n_members * sizeof(protobuf_c_boolean), state->allocator);
843  if (!tmp) {
844  return state_error(state, t, "Malloc failure.");
845  }
846  STRUCT_MEMBER(protobuf_c_boolean *, msg, state->field->offset) = tmp;
847  tmp[n_members - 1] = t->boolean;
848  return STATE_OPEN;
849  } else {
850  STRUCT_MEMBER(protobuf_c_boolean, msg, state->field->offset)
851  = t->boolean;
852  return STATE_OPEN;
853  }
854 
855  }
856  return state_error(state, t,
857  "'%s' is not a boolean field.", state->field->name);
858  break;
859 
860  case TOK_QUOTED:
861  if (state->field->type == PROTOBUF_C_TYPE_BYTES) {
862  ProtobufCBinaryData *pbbd;
863 
864  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
865  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
866  n_members = STRUCT_MEMBER(size_t, msg,
867  state->field->quantifier_offset);
868  pbbd = local_realloc(
869  STRUCT_MEMBER(ProtobufCBinaryData *, msg, state->field->offset),
870  (n_members - 1) * sizeof(ProtobufCBinaryData),
871  n_members * sizeof(ProtobufCBinaryData), state->allocator);
872  if (!pbbd) {
873  return state_error(state, t, "Malloc failure.");
874  }
875  STRUCT_MEMBER(ProtobufCBinaryData *, msg, state->field->offset)
876  = pbbd;
877  pbbd[n_members - 1].data = ST_ALLOC(t->qs->len);
878  if (!pbbd[n_members - 1].data) {
879  return state_error(state, t, "Malloc failure.");
880  }
881  memcpy(pbbd[n_members - 1].data, t->qs->data, t->qs->len);
882  pbbd[n_members - 1].len = t->qs->len;
883  return STATE_OPEN;
884  } else {
885  pbbd = STRUCT_MEMBER_PTR(ProtobufCBinaryData, msg,
886  state->field->offset);
887  pbbd->data = ST_ALLOC(t->qs->len);
888  if (!pbbd->data) {
889  return state_error(state, t, "Malloc failure.");
890  }
891  memcpy(pbbd->data, t->qs->data, t->qs->len);
892  pbbd->len = t->qs->len;
893  return STATE_OPEN;
894  }
895 
896  } else if (state->field->type == PROTOBUF_C_TYPE_STRING) {
897  if (state->field->label == PROTOBUF_C_LABEL_OPTIONAL) {
898  /* Do optional member accounting. */
899  if (STRUCT_MEMBER(unsigned char *, msg, state->field->offset)
900  && (STRUCT_MEMBER(unsigned char *, msg, state->field->offset)
901  != state->field->default_value)) {
902  return state_error(state, t,
903  "'%s' has already been assigned.", state->field->name);
904  }
905  }
906  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
907  unsigned char **s;
908 
909  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
910  n_members = STRUCT_MEMBER(size_t, msg,
911  state->field->quantifier_offset);
912  s = local_realloc(
913  STRUCT_MEMBER(unsigned char **, msg, state->field->offset),
914  (n_members - 1) * sizeof(unsigned char *),
915  n_members * sizeof(unsigned char *), state->allocator);
916  if (!s) {
917  return state_error(state, t, "Malloc failure.");
918  }
919  STRUCT_MEMBER(unsigned char **, msg, state->field->offset) = s;
920  s[n_members - 1] = ST_ALLOC(t->qs->len + 1);
921  if (!s[n_members - 1]) {
922  return state_error(state, t, "Malloc failure.");
923  }
924  memcpy(s[n_members - 1], t->qs->data, t->qs->len);
925  s[n_members - 1][t->qs->len] = '\0';
926  return STATE_OPEN;
927  } else {
928  unsigned char *s;
929 
930  s = ST_ALLOC(t->qs->len + 1);
931  if (!s) {
932  return state_error(state, t, "Malloc failure.");
933  }
934  memcpy(s, t->qs->data, t->qs->len);
935  s[t->qs->len] = '\0';
936  STRUCT_MEMBER(unsigned char *, msg, state->field->offset) = s;
937  return STATE_OPEN;
938  }
939 
940  }
941  return state_error(state, t,
942  "'%s' is not a string or byte field.", state->field->name);
943  break;
944 
945  case TOK_NUMBER:
946  switch (state->field->type) {
947  case PROTOBUF_C_TYPE_INT32:
948  case PROTOBUF_C_TYPE_UINT32:
949  case PROTOBUF_C_TYPE_FIXED32:
950  val = strtoul(t->number, &end, 10);
951  if (*end != '\0' || val > (uint64_t)UINT32_MAX) {
952  return state_error(state, t,
953  "Unable to convert '%s' for field '%s'.",
954  t->number, state->field->name);
955  }
956  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
957  uint32_t *vals;
958 
959  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
960  n_members = STRUCT_MEMBER(size_t, msg,
961  state->field->quantifier_offset);
962  vals = local_realloc(
963  STRUCT_MEMBER(uint32_t *, msg, state->field->offset),
964  (n_members - 1) * sizeof(uint32_t),
965  n_members * sizeof(uint32_t), state->allocator);
966  if (!vals) {
967  return state_error(state, t, "Malloc failure.");
968  }
969  STRUCT_MEMBER(uint32_t *, msg, state->field->offset) = vals;
970  vals[n_members - 1] = (uint32_t)val;
971  return STATE_OPEN;
972  } else {
973  STRUCT_MEMBER(uint32_t, msg, state->field->offset) = (uint32_t)val;
974  return STATE_OPEN;
975  }
976  break;
977 
978  case PROTOBUF_C_TYPE_SINT32:
979  case PROTOBUF_C_TYPE_SFIXED32:
980  val = strtol(t->number, &end, 10);
981  if (*end != '\0' || val < INT32_MIN || val > INT32_MAX) {
982  return state_error(state, t,
983  "Unable to convert '%s' for field '%s'.",
984  t->number, state->field->name);
985  }
986  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
987  int32_t *vals;
988 
989  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
990  n_members = STRUCT_MEMBER(size_t, msg,
991  state->field->quantifier_offset);
992  vals = local_realloc(
993  STRUCT_MEMBER(int32_t *, msg, state->field->offset),
994  (n_members - 1) * sizeof(int32_t),
995  n_members * sizeof(int32_t), state->allocator);
996  if (!vals) {
997  return state_error(state, t, "Malloc failure.");
998  }
999  STRUCT_MEMBER(int32_t *, msg, state->field->offset) = vals;
1000  vals[n_members - 1] = (uint32_t)val;
1001  return STATE_OPEN;
1002  } else {
1003  STRUCT_MEMBER(int32_t, msg, state->field->offset) = val;
1004  return STATE_OPEN;
1005  }
1006  break;
1007 
1008  case PROTOBUF_C_TYPE_INT64:
1009  case PROTOBUF_C_TYPE_UINT64:
1010  case PROTOBUF_C_TYPE_FIXED64:
1011  val = strtoull(t->number, &end, 10);
1012  if (*end != '\0') {
1013  return state_error(state, t,
1014  "Unable to convert '%s' for field '%s'.",
1015  t->number, state->field->name);
1016  }
1017  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
1018  uint64_t *vals;
1019 
1020  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
1021  n_members = STRUCT_MEMBER(size_t, msg,
1022  state->field->quantifier_offset);
1023  vals = local_realloc(
1024  STRUCT_MEMBER(uint64_t *, msg, state->field->offset),
1025  (n_members - 1) * sizeof(uint64_t),
1026  n_members * sizeof(uint64_t), state->allocator);
1027  if (!vals) {
1028  return state_error(state, t, "Malloc failure.");
1029  }
1030  STRUCT_MEMBER(uint64_t *, msg, state->field->offset) = vals;
1031  vals[n_members - 1] = val;
1032  return STATE_OPEN;
1033  } else {
1034  STRUCT_MEMBER(uint64_t, msg, state->field->offset) = val;
1035  return STATE_OPEN;
1036  }
1037  break;
1038 
1039  case PROTOBUF_C_TYPE_SINT64:
1040  case PROTOBUF_C_TYPE_SFIXED64:
1041  val = strtoll(t->number, &end, 10);
1042  if (*end != '\0') {
1043  return state_error(state, t,
1044  "Unable to convert '%s' for field '%s'.",
1045  t->number, state->field->name);
1046  }
1047  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
1048  int64_t *vals;
1049 
1050  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
1051  n_members = STRUCT_MEMBER(size_t, msg,
1052  state->field->quantifier_offset);
1053  vals = local_realloc(
1054  STRUCT_MEMBER(int64_t *, msg, state->field->offset),
1055  (n_members - 1) * sizeof(int64_t),
1056  n_members * sizeof(int64_t), state->allocator);
1057  if (!vals) {
1058  return state_error(state, t, "Malloc failure.");
1059  }
1060  STRUCT_MEMBER(int64_t *, msg, state->field->offset) = vals;
1061  vals[n_members - 1] = val;
1062  return STATE_OPEN;
1063  } else {
1064  STRUCT_MEMBER(int64_t, msg, state->field->offset) = val;
1065  return STATE_OPEN;
1066  }
1067  break;
1068 
1069  case PROTOBUF_C_TYPE_FLOAT:
1070  {
1071  float val, *vals;
1072 
1073  errno = 0;
1074  val = strtof(t->number, &end);
1075  if (*end != '\0' || errno == ERANGE) {
1076  return state_error(state, t,
1077  "Unable to convert '%s' for field '%s'.",
1078  t->number, state->field->name);
1079  }
1080  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
1081  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
1082  n_members = STRUCT_MEMBER(size_t, msg,
1083  state->field->quantifier_offset);
1084  vals = local_realloc(
1085  STRUCT_MEMBER(float *, msg, state->field->offset),
1086  (n_members - 1) * sizeof(float),
1087  n_members * sizeof(float), state->allocator);
1088  if (!vals) {
1089  return state_error(state, t, "Malloc failure.");
1090  }
1091  STRUCT_MEMBER(float *, msg, state->field->offset) = vals;
1092  vals[n_members - 1] = val;
1093  return STATE_OPEN;
1094  } else {
1095  STRUCT_MEMBER(float, msg, state->field->offset) = val;
1096  return STATE_OPEN;
1097  }
1098  }
1099  break;
1100 
1101  case PROTOBUF_C_TYPE_DOUBLE:
1102  {
1103  double val,*vals;
1104 
1105  errno = 0;
1106  val = strtod(t->number, &end);
1107  if (*end != '\0' || errno == ERANGE) {
1108  return state_error(state, t,
1109  "Unable to convert '%s' for field '%s'.",
1110  t->number, state->field->name);
1111  }
1112  if (state->field->label == PROTOBUF_C_LABEL_REPEATED) {
1113  STRUCT_MEMBER(size_t, msg, state->field->quantifier_offset) += 1;
1114  n_members = STRUCT_MEMBER(size_t, msg,
1115  state->field->quantifier_offset);
1116  vals = local_realloc(
1117  STRUCT_MEMBER(double *, msg, state->field->offset),
1118  (n_members - 1) * sizeof(double),
1119  n_members * sizeof(double), state->allocator);
1120  if (!vals) {
1121  return state_error(state, t, "Malloc failure.");
1122  }
1123  STRUCT_MEMBER(double *, msg, state->field->offset) = vals;
1124  vals[n_members - 1] = val;
1125  return STATE_OPEN;
1126  } else {
1127  STRUCT_MEMBER(double, msg, state->field->offset) = val;
1128  return STATE_OPEN;
1129  }
1130  }
1131  break;
1132 
1133  default:
1134  return state_error(state, t,
1135  "'%s' is not a numeric field.", state->field->name);
1136  break;
1137  }
1138  break;
1139 
1140  default:
1141  return state_error(state, t,
1142  "Expected value; found '%s' instead.",
1143  token2txt(t));
1144  break;
1145  }
1146 }
1147 
1152 static StateId(* states[])(State *, Token *) = {
1153  [STATE_OPEN] = state_open,
1156 };
1157  /* End of state group. */
1159 
1182 static ProtobufCMessage *
1183 protobuf_c_text_parse(const ProtobufCMessageDescriptor *descriptor,
1184  Scanner *scanner,
1185  ProtobufCTextError *result,
1186  ProtobufCAllocator *allocator)
1187 {
1188  Token token;
1189  State state;
1190  StateId state_id;
1191  ProtobufCMessage *msg = NULL;
1192 
1193  result->error_txt = NULL;
1194  result->complete = -1; /* -1 means the check wasn't performed. */
1195 
1196  state_id = STATE_OPEN;
1197  if (!state_init(&state, scanner, descriptor, allocator)) {
1198  return NULL;
1199  }
1200 
1201  while (state_id != STATE_DONE) {
1202  token = scan(scanner, allocator);
1203  if (token.id == TOK_MALLOC_ERR) {
1204  token_free(&token, allocator);
1205  state_error(&state, &token, "String unescape or malloc failure.");
1206  break;
1207  }
1208  state_id = states[state_id](&state, &token);
1209  token_free(&token, allocator);
1210  }
1211 
1212  scanner_free(scanner, allocator);
1213  if (state.error) {
1214  result->error_txt = state.error_str;
1215  if (msg) {
1216  protobuf_c_message_free_unpacked(state.msgs[0], allocator);
1217  }
1218  } else {
1219  msg = state.msgs[0];
1220 #ifdef HAVE_PROTOBUF_C_MESSAGE_CHECK
1221  result->complete = protobuf_c_message_check(msg);
1222 #endif
1223  }
1224  state_free(&state);
1225  return msg;
1226 }
1227  /* End of base-parse group. */
1229 
1230 /* See .h file for API docs. */
1231 
1232 ProtobufCMessage *
1233 protobuf_c_text_from_file(const ProtobufCMessageDescriptor *descriptor,
1234  FILE *msg_file,
1235  ProtobufCTextError *result,
1236  ProtobufCAllocator *allocator)
1237 {
1238  Scanner scanner;
1239 
1240  scanner_init_file(&scanner, msg_file);
1241  return protobuf_c_text_parse(descriptor, &scanner, result, allocator);
1242 }
1243 
1244 ProtobufCMessage *
1245 protobuf_c_text_from_string(const ProtobufCMessageDescriptor *descriptor,
1246  char *msg,
1247  ProtobufCTextError *result,
1248  ProtobufCAllocator *allocator)
1249 {
1250  Scanner scanner;
1251 
1252  scanner_init_string(&scanner, msg);
1253  return protobuf_c_text_parse(descriptor, &scanner, result, allocator);
1254 }
A closing brace.
Definition: parse.re:95
TokenId id
The kind of token.
Definition: parse.re:109
int max_msg
Size of the message stack.
Definition: parse.re:492
int current_msg
Index on the message stack of the current message.
Definition: parse.re:490
ProtobufCAllocator * allocator
allocator functions.
Definition: parse.re:495
A memory allocation error occurred.
Definition: parse.re:100
FILE * f
For file scanners, this is the input source.
Definition: parse.re:188
#define PBC_FREE(ptr)
Free possibly using the pbc allocator.
#define STRUCT_MEMBER(member_type, struct_p, struct_offset)
Return a field from a message based on offset and type.
static ProtobufCMessage * protobuf_c_text_parse(const ProtobufCMessageDescriptor *descriptor, Scanner *scanner, ProtobufCTextError *result, ProtobufCAllocator *allocator)
Base function for the API functions.
Definition: parse.re:1183
int error
Notes an error has occurred.
Definition: parse.re:496
static int fill(Scanner *scanner, ProtobufCAllocator *allocator)
Function to request more data from input source in Scanner.
Definition: parse.re:342
static void * local_realloc(void *ptr, size_t old_size, size_t size, ProtobufCAllocator *allocator)
A realloc implementation using ProtobufCAllocator functions.
Definition: parse.re:56
ProtobufCMessage ** msgs
The message stack.
Definition: parse.re:493
A quoted string.
Definition: parse.re:97
static StateId(* states[])(State *, Token *)
Table of states and actions.
Definition: parse.re:1152
int complete
Reports whether the message is complete (if supported):
static StateId state_value(State *state, Token *t)
Expect a quoted string, enum (bareword) or boolean.
Definition: parse.re:771
Structure for reporting API errors.
unsigned char * limit
Where the buffer ends.
Definition: parse.re:186
#define ST_ALLOC(size)
Allocate possibly using the pbc allocator (state members).
Ready to start a new statement or close a nested message.
Definition: parse.re:470
char * bareword
TOK_BAREWORD: string with bareword in it.
Definition: parse.re:112
unsigned char * marker
Used for backtracking.
Definition: parse.re:184
static int state_init(State *state, Scanner *scanner, const ProtobufCMessageDescriptor *descriptor, ProtobufCAllocator *allocator)
Initialise a State struct.
Definition: parse.re:510
static void state_free(State *state)
Free internal data in a State struct.
Definition: parse.re:550
An opening brace.
Definition: parse.re:94
Maintains state for successive calls to scan() .
Definition: parse.re:182
unsigned char * buffer
The buffer holding the data being parsed.
Definition: parse.re:185
char * number
TOK_NUMBER: string with the number.
Definition: parse.re:111
static StateId state_assignment(State *state, Token *t)
Expect a colon or opening brace.
Definition: parse.re:663
#define CHUNK
Amount of data to read from a file each time.
Definition: parse.re:326
Internal utility header file.
ProtobufCMessage * protobuf_c_text_from_string(const ProtobufCMessageDescriptor *descriptor, char *msg, ProtobufCTextError *result, ProtobufCAllocator *allocator)
Import a text format protobuf from a string into a ProtobufCMessage.
Definition: parse.re:1245
static const char * token2txt(Token *t)
Converts a Token to a string based on its type.
Definition: parse.re:128
static void scanner_init_file(Scanner *scanner, FILE *f)
Initialise a Scanner from a FILE.
Definition: parse.re:202
unsigned char * cursor
Where we are in the buffer.
Definition: parse.re:183
Assign the scalar.
Definition: parse.re:473
Nothing more to read or there's been an error.
Definition: parse.re:474
A number.
Definition: parse.re:98
int line
Current line number being parsed.
Definition: parse.re:190
#define STATE_ERROR_STR_MAX
Max size of an error message.
Definition: parse.re:478
Maintain state for the FSM.
Definition: parse.re:484
unsigned char * token
Pointer to the start of the current token.
Definition: parse.re:187
char * error_str
Text of error.
Definition: parse.re:497
static void scanner_init_string(Scanner *scanner, char *buf)
Initialise a Scanner from a string.
Definition: parse.re:217
static void scanner_free(Scanner *scanner, ProtobufCAllocator *allocator)
Free data internal to the Scanner instance.
Definition: parse.re:233
static StateId state_open(State *state, Token *t)
Expect an element name (bareword) or a closing brace.
Definition: parse.re:610
ProtobufCBinaryData * qs
TOK_QUOTED: Unescaped quoted string with the quotes removed.
Definition: parse.re:113
A token and its value.
Definition: parse.re:108
The unquoted form of "true" and "false".
Definition: parse.re:99
A colon.
Definition: parse.re:96
#define ST_FREE(ptr)
Free possibly using the pbc allocator (state members).
char * error_txt
String with error message.
Ready to assign a scalar or a nested message.
Definition: parse.re:472
End of file.
Definition: parse.re:92
const ProtobufCFieldDescriptor * field
After finding a TOK_BAREWORD in a STATE_OPEN field is set to the field in the message that matches th...
Definition: parse.re:486
A bare, unquoted single word.
Definition: parse.re:93
static ProtobufCBinaryData * unesc_str(unsigned char *src, int len, ProtobufCAllocator *allocator)
Unescape string.
Definition: parse.re:253
ProtobufCMessage * protobuf_c_text_from_file(const ProtobufCMessageDescriptor *descriptor, FILE *msg_file, ProtobufCTextError *result, ProtobufCAllocator *allocator)
Import a text format protobuf from a FILE into a ProtobufCMessage.
Definition: parse.re:1233
static Token scan(Scanner *scanner, ProtobufCAllocator *allocator)
Generated lexer.
Definition: parse.re:393
static void token_free(Token *t, ProtobufCAllocator *allocator)
Frees memory allocated in a Token instance.
Definition: parse.re:161
StateId
StateId enumeration.
Definition: parse.re:469
Scanner * scanner
Tracks state for the scanner.
Definition: parse.re:485
#define PBC_ALLOC(size)
Allocate possibly using the pbc allocator.
static StateId state_error(State *state, Token *t, char *error_fmt,...) __attribute__((format(printf
Handle an error in the FSM.
Definition: parse.re:575
TokenId
Token types.
Definition: parse.re:91
#define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset)
Return a pointer to a field in a message based on offset and type.
bool boolean
TOK_BOOLEAN: true or false .
Definition: parse.re:115