json.c 3.32 KB
Newer Older
Julian Rother's avatar
Julian Rother committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "../util.h"

static char *skip_ws(char *s)
{
	for (; *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'; s ++);
	return s;
}

static char *skip(char *s)
{
	s = skip_ws(s);
	if (*s == '"')
	{
		for (s++; *s && *s != '"'; s ++)
			if (s[0] == '\\' && s[1] == '"')
				s += 1;
		if (*s == '"')
			s ++;
	}
	else if (*s == '-' || (*s >= '1' && *s <= '9'))
		for (s ++; (*s >= '0' && *s <= '9') || *s == 'e' || *s == 'E' || *s == '.' ||
				*s == '-' || *s == '+'; s ++);
	else if (*s == '[')
	{
		do
			s = skip_ws(skip(s+1));
		while (*s == ',');
		if (*s == ']')
			s ++;
	}
	else if (*s == '{')
	{
		do
		{
			s = skip_ws(skip(s+1));
			if (*s == ':')
				s ++;
			s = skip_ws(skip(s));
		}
		while (*s == ',');
		if (*s == '}')
			s ++;
	}
	else if (!strncmp(s, SL("true")))
		return s+4;
	else if (!strncmp(s, SL("false")))
		return s+5;
	else if (!strncmp(s, SL("null")))
		return s+4;
	return s;
}

size_t parse_escape(char *s, uint32_t *code)
{
	char buf[4] = {};
	if (*s == 'u')
	{
		if (!(buf[0] = s[1]) ||
				!(buf[1] = s[2]) ||
				!(buf[2] = s[3]) ||
				!(buf[3] = s[4]))
			return 0;
		*code = strtol(buf, 0, 16);
		return 5;
	}
	switch (*s)
	{
		case 'b': *code = '\b'; break;
		case 'f': *code = '\f'; break;
		case 'n': *code = '\n'; break;
		case 'r': *code = '\r'; break;
		case 't': *code = '\t'; break;
		default:
			*code = *s;
	}
	return 1;
}

#define utf8_len(code) utf8_enc(code, 0)
size_t utf8_enc(uint32_t code, char *buf)
{
	char _buf[4];
	if (!buf)
		buf = _buf;
	if (code <= 0x7f)
	{
		buf[0] = code;
		return 1;
	}
	else if (code <= 0x7ff)
	{
		buf[0] = 0xc0 | (code >> 6);
		buf[1] = 0x80 | (code & 0x3f);
		return 2;
	}
	else if (code <= 0xffff)
	{
		buf[0] = 0xe0 | (code >> 12);
		buf[1] = 0x80 | ((code >> 6) & 0x3f);
		buf[2] = 0x80 | (code & 0x3f);
		return 3;
	}
	else
		return 0;
}

ssize_t jbin(char *s, char *buf, size_t len)
{
	int i, tmp;
	uint32_t code;
	if (!s)
		return -1;
	s = skip_ws(s);
	if (*s != '"')
		return -1;
	for (i = 0, s ++; *s && *s != '"' && i+1 < len;)
		if (*s == '\\')
		{
			if (!(tmp = parse_escape(++s, &code)))
				return -1;
			s += tmp;
			if (i+utf8_len(code) >= len)
				return -1;
			i += utf8_enc(code, buf+i);
		}
		else
			buf[i ++] = *(s ++);
	if (*s != '"')
		return -1;
	return i;
}

Julian Rother's avatar
Julian Rother committed
138
char *jstrb(char *s, char *err, char *buf, size_t len)
Julian Rother's avatar
Julian Rother committed
139 140
{
	ssize_t res;
Julian Rother's avatar
Julian Rother committed
141 142
	res = jbin(s, buf, len);
	if (res == -1 || res+1 >= len)
Julian Rother's avatar
Julian Rother committed
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
		return err;
	buf[res] = 0;
	return buf;
}

int jint(char *s, int err)
{
	if (!s)
		return err;
	if (!strncmp(s, SL("true")))
		return 1;
	if (!strncmp(s, SL("false")))
		return 0;
	if (!strncmp(s, SL("null")))
		return 0;
	return strtol(s, 0, 10);
}

char *jenter(char *s)
{
	if (!s)
		return 0;
	s = skip_ws(s);
	if (*s == '[' || *s == '{')
		return s+1;
	return 0;
}

char *jnext(char *s)
{
	if (!s)
		return 0;
	s = skip_ws(skip(s));
	if (*s == ':')
		s = skip_ws(skip(s+1));
	if (*s == ',')
		return s+1;
	else
		return 0;
}

char *jvalue(char *s)
{
	if (!s)
		return 0;
	s = skip_ws(skip(s));
	if (*s != ':')
		return 0;
	return s+1;
}

char *jlookup(char *s, char *key)
{
Julian Rother's avatar
Julian Rother committed
196
	static __thread char buf[JSON_KEY_SIZE];
Julian Rother's avatar
Julian Rother committed
197 198 199 200 201 202
	if (!s)
		return 0;
	s = skip_ws(s);
	if (*s != '{')
		return 0;
	for (s = skip_ws(s+1); s; s = jnext(s))
Julian Rother's avatar
Julian Rother committed
203
		if (!strcmp(jstrb(s, "INVALID KEY", BL(buf)), key))
Julian Rother's avatar
Julian Rother committed
204 205 206
			return jvalue(s);
	return 0;
}