Blame ext/solv_jsonparser.c

Packit Service ff689b
/*
Packit Service ff689b
 * solv_jsonparser.c
Packit Service ff689b
 *
Packit Service ff689b
 * Simple JSON stream parser
Packit Service ff689b
 *
Packit Service ff689b
 * Copyright (c) 2018, SUSE LLC
Packit Service ff689b
 *
Packit Service ff689b
 * This program is licensed under the BSD license, read LICENSE.BSD
Packit Service ff689b
 * for further information
Packit Service ff689b
 */
Packit Service ff689b
Packit Service ff689b
#include <stdio.h>
Packit Service ff689b
#include <stdlib.h>
Packit Service ff689b
Packit Service ff689b
#include "util.h"
Packit Service ff689b
#include "solv_jsonparser.h"
Packit Service ff689b
Packit Service ff689b
void
Packit Service ff689b
jsonparser_init(struct solv_jsonparser *jp, FILE *fp)
Packit Service ff689b
{
Packit Service ff689b
  memset(jp, 0, sizeof(*jp));
Packit Service ff689b
  jp->fp = fp;
Packit Service ff689b
  jp->state = JP_START;
Packit Service ff689b
  jp->line = jp->nextline = 1;
Packit Service ff689b
  jp->nextc = ' ';
Packit Service ff689b
  queue_init(&jp->stateq);
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
void
Packit Service ff689b
jsonparser_free(struct solv_jsonparser *jp)
Packit Service ff689b
{
Packit Service ff689b
  solv_free(jp->space);
Packit Service ff689b
  queue_free(&jp->stateq);
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static void
Packit Service ff689b
savec(struct solv_jsonparser *jp, char c)
Packit Service ff689b
{
Packit Service ff689b
  if (jp->nspace == jp->aspace)
Packit Service ff689b
    {
Packit Service ff689b
      jp->aspace += 256;
Packit Service ff689b
      jp->space = solv_realloc(jp->space, jp->aspace);
Packit Service ff689b
    }
Packit Service ff689b
  jp->space[jp->nspace++] = c;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static void
Packit Service ff689b
saveutf8(struct solv_jsonparser *jp, int c)
Packit Service ff689b
{
Packit Service ff689b
  int i;
Packit Service ff689b
  if (c < 0x80)
Packit Service ff689b
    {
Packit Service ff689b
      savec(jp, c);
Packit Service ff689b
      return;
Packit Service ff689b
    }
Packit Service ff689b
  i = c < 0x800 ? 1 : c < 0x10000 ? 2 : 3;
Packit Service ff689b
  savec(jp, (0x1f80 >> i) | (c >> (6 * i)));
Packit Service ff689b
  while (--i >= 0)
Packit Service ff689b
    savec(jp, 0x80 | ((c >> (6 * i)) & 0x3f));
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static inline int
Packit Service ff689b
nextc(struct solv_jsonparser *jp)
Packit Service ff689b
{
Packit Service ff689b
  int c = getc(jp->fp);
Packit Service ff689b
  if (c == '\n')
Packit Service ff689b
    jp->nextline++;
Packit Service ff689b
  return c;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static int
Packit Service ff689b
skipspace(struct solv_jsonparser *jp)
Packit Service ff689b
{
Packit Service ff689b
  int c = jp->nextc;
Packit Service ff689b
  jp->nextc = ' ';
Packit Service ff689b
  while (c == ' ' || c == '\t' || c == '\r' || c == '\n')
Packit Service ff689b
    c = nextc(jp);
Packit Service ff689b
  jp->line = jp->nextline;
Packit Service ff689b
  return c;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static int
Packit Service ff689b
parseliteral(struct solv_jsonparser *jp, int c)
Packit Service ff689b
{
Packit Service ff689b
  size_t nspace = jp->nspace;
Packit Service ff689b
  savec(jp, c);
Packit Service ff689b
  for (;;)
Packit Service ff689b
    {
Packit Service ff689b
      c = nextc(jp);
Packit Service ff689b
      if (c < 'a' || c > 'z')
Packit Service ff689b
	break;
Packit Service ff689b
      savec(jp, c);
Packit Service ff689b
    }
Packit Service ff689b
  jp->nextc = c;
Packit Service ff689b
  savec(jp, 0);
Packit Service ff689b
  if (!strcmp(jp->space + nspace, "true"))
Packit Service ff689b
    return JP_BOOL;
Packit Service ff689b
  if (!strcmp(jp->space + nspace, "false"))
Packit Service ff689b
    return JP_BOOL;
Packit Service ff689b
  if (!strcmp(jp->space + nspace, "null"))
Packit Service ff689b
    return JP_NULL;
Packit Service ff689b
  return JP_ERROR;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static int
Packit Service ff689b
parsenumber(struct solv_jsonparser *jp, int c)
Packit Service ff689b
{
Packit Service ff689b
  savec(jp, c);
Packit Service ff689b
  for (;;)
Packit Service ff689b
    {
Packit Service ff689b
      c = nextc(jp);
Packit Service ff689b
      if ((c < '0' || c > '9') && c != '+' && c != '-' && c != '.' && c != 'e' && c != 'E')
Packit Service ff689b
	break;
Packit Service ff689b
      savec(jp, c);
Packit Service ff689b
    }
Packit Service ff689b
  jp->nextc = c;
Packit Service ff689b
  savec(jp, 0);
Packit Service ff689b
  return JP_NUMBER;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static int
Packit Service ff689b
parseutf8(struct solv_jsonparser *jp, int surrogate)
Packit Service ff689b
{
Packit Service ff689b
  int c, i, r = 0;
Packit Service ff689b
  /* parse 4-digit hex */
Packit Service ff689b
  for (i = 0; i < 4; i++)
Packit Service ff689b
    {
Packit Service ff689b
      c = nextc(jp);
Packit Service ff689b
      if (c >= '0' && c <= '9')
Packit Service ff689b
	c -= '0';
Packit Service ff689b
      else if (c >= 'a' && c <= 'f')
Packit Service ff689b
	c -= 'a' - 10;
Packit Service ff689b
      else if (c >= 'A' && c <= 'F')
Packit Service ff689b
	c -= 'A' - 10;
Packit Service ff689b
      else
Packit Service ff689b
	return -1;
Packit Service ff689b
      r = (r << 4) | c;
Packit Service ff689b
    }
Packit Service ff689b
  if (!surrogate && r >= 0xd800 && r < 0xdc00)
Packit Service ff689b
    {
Packit Service ff689b
      /* utf16 surrogate pair encodes 0x10000 - 0x10ffff */
Packit Service ff689b
      int r2;
Packit Service ff689b
      if (nextc(jp) != '\\' || nextc(jp) != 'u' || (r2 = parseutf8(jp, 1)) < 0xdc00 || r2 >= 0xe000)
Packit Service ff689b
	return -1;
Packit Service ff689b
      r = 0x10000 + ((r & 0x3ff) << 10 | (r2 & 0x3ff));
Packit Service ff689b
    }
Packit Service ff689b
  return r;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static int
Packit Service ff689b
parsestring(struct solv_jsonparser *jp)
Packit Service ff689b
{
Packit Service ff689b
  int c;
Packit Service ff689b
  for (;;)
Packit Service ff689b
    {
Packit Service ff689b
      if ((c = nextc(jp)) < 32)
Packit Service ff689b
	return JP_ERROR;
Packit Service ff689b
      if (c == '"')
Packit Service ff689b
	break;
Packit Service ff689b
      if (c == '\\')
Packit Service ff689b
	{
Packit Service ff689b
	  switch (c = nextc(jp))
Packit Service ff689b
	    {
Packit Service ff689b
	    case '"':
Packit Service ff689b
	    case '\\':
Packit Service ff689b
	    case '/':
Packit Service ff689b
	    case '\n':
Packit Service ff689b
	      break;
Packit Service ff689b
	    case 'b':
Packit Service ff689b
	      c = '\b';
Packit Service ff689b
	      break;
Packit Service ff689b
	    case 'f':
Packit Service ff689b
	      c = '\f';
Packit Service ff689b
	      break;
Packit Service ff689b
	    case 'n':
Packit Service ff689b
	      c = '\n';
Packit Service ff689b
	      break;
Packit Service ff689b
	    case 'r':
Packit Service ff689b
	      c = '\r';
Packit Service ff689b
	      break;
Packit Service ff689b
	    case 't':
Packit Service ff689b
	      c = '\t';
Packit Service ff689b
	      break;
Packit Service ff689b
	    case 'u':
Packit Service ff689b
	      if ((c = parseutf8(jp, 0)) < 0)
Packit Service ff689b
		return JP_ERROR;
Packit Service ff689b
	      saveutf8(jp, c);
Packit Service ff689b
	      continue;
Packit Service ff689b
	    default:
Packit Service ff689b
	      return JP_ERROR;
Packit Service ff689b
	    }
Packit Service ff689b
	}
Packit Service ff689b
      savec(jp, c);
Packit Service ff689b
    }
Packit Service ff689b
  savec(jp, 0);
Packit Service ff689b
  return JP_STRING;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static int
Packit Service ff689b
parsevalue(struct solv_jsonparser *jp)
Packit Service ff689b
{
Packit Service ff689b
  int c = skipspace(jp);
Packit Service ff689b
  if (c == '"')
Packit Service ff689b
    return parsestring(jp);
Packit Service ff689b
  if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
Packit Service ff689b
    return parsenumber(jp, c);
Packit Service ff689b
  if ((c >= 'a' && c <= 'z'))
Packit Service ff689b
    return parseliteral(jp, c);
Packit Service ff689b
  if (c == '[')
Packit Service ff689b
    return JP_ARRAY;
Packit Service ff689b
  if (c == '{')
Packit Service ff689b
    return JP_OBJECT;
Packit Service ff689b
  if (c == ']')
Packit Service ff689b
    return JP_ARRAY_END;
Packit Service ff689b
  if (c == '}')
Packit Service ff689b
    return JP_OBJECT_END;
Packit Service ff689b
  return JP_ERROR;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
int
Packit Service ff689b
jsonparser_parse(struct solv_jsonparser *jp)
Packit Service ff689b
{
Packit Service ff689b
  int type;
Packit Service ff689b
  size_t nspace;
Packit Service ff689b
Packit Service ff689b
  jp->depth = jp->stateq.count;
Packit Service ff689b
  jp->key = jp->value = 0;
Packit Service ff689b
  jp->keylen = jp->valuelen = 0;
Packit Service ff689b
  nspace = jp->nspace = 0;
Packit Service ff689b
Packit Service ff689b
  if (jp->state == JP_END)
Packit Service ff689b
    return JP_END;
Packit Service ff689b
  if (jp->state == JP_START)
Packit Service ff689b
    jp->state = JP_END;
Packit Service ff689b
  type = parsevalue(jp);
Packit Service ff689b
  if (type <= 0)
Packit Service ff689b
    return JP_ERROR;
Packit Service ff689b
  if (type == JP_OBJECT_END || type == JP_ARRAY_END)
Packit Service ff689b
    {
Packit Service ff689b
      if (jp->state != type - 1)
Packit Service ff689b
        return JP_ERROR;
Packit Service ff689b
      jp->state = queue_pop(&jp->stateq);
Packit Service ff689b
    }
Packit Service ff689b
  else if (jp->state == JP_OBJECT)
Packit Service ff689b
    {
Packit Service ff689b
      nspace = jp->nspace;
Packit Service ff689b
      if (type != JP_STRING)
Packit Service ff689b
	return JP_ERROR;
Packit Service ff689b
      if (skipspace(jp) != ':')
Packit Service ff689b
	return JP_ERROR;
Packit Service ff689b
      type = parsevalue(jp);
Packit Service ff689b
      if (type == JP_OBJECT_END || type == JP_ARRAY_END)
Packit Service ff689b
	return JP_ERROR;
Packit Service ff689b
      jp->key = jp->space;
Packit Service ff689b
      jp->keylen = nspace - 1;
Packit Service ff689b
    }
Packit Service ff689b
  if (type == JP_STRING || type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
Packit Service ff689b
    {
Packit Service ff689b
      jp->value = jp->space + nspace;
Packit Service ff689b
      jp->valuelen = jp->nspace - nspace - 1;
Packit Service ff689b
    }
Packit Service ff689b
  if (type == JP_OBJECT || type == JP_ARRAY)
Packit Service ff689b
    {
Packit Service ff689b
      queue_push(&jp->stateq, jp->state);
Packit Service ff689b
      jp->state = type;
Packit Service ff689b
    }
Packit Service ff689b
  else if (jp->state == JP_OBJECT || jp->state == JP_ARRAY)
Packit Service ff689b
    {
Packit Service ff689b
      int c = skipspace(jp);
Packit Service ff689b
      if (c == (jp->state == JP_OBJECT ? '}' : ']'))
Packit Service ff689b
	jp->nextc = c;
Packit Service ff689b
      else if (c != ',')
Packit Service ff689b
	return JP_ERROR;
Packit Service ff689b
    }
Packit Service ff689b
  return type;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
int
Packit Service ff689b
jsonparser_skip(struct solv_jsonparser *jp, int type)
Packit Service ff689b
{
Packit Service ff689b
  if (type == JP_ARRAY || type == JP_OBJECT)
Packit Service ff689b
    {
Packit Service ff689b
      int depth = jp->depth + 1, endtype = type + 1;
Packit Service ff689b
      while (type > 0 && (type != endtype || jp->depth != depth))
Packit Service ff689b
        type = jsonparser_parse(jp);
Packit Service ff689b
    }
Packit Service ff689b
  return type;
Packit Service ff689b
}
Packit Service ff689b