summaryrefslogtreecommitdiffstats
path: root/src/json.c
blob: aae6f5d157fd38cc5d151a0e2880d39834cdf71b (plain) (blame)
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
#ifndef DC_REALLOC_K
#define DC_REALLOC_K 1.5
#endif
struct dc_json { /* does not care about syntax, only purpose is to detect objects for libcjson */
	char * buf;	/* internal buffer */
	size_t bufcap;	/* internal buffer capacity */
	size_t nest;	/* internal nesting depth of whatevery type: object or array */
	size_t instr;	/* internal if we are currently in a string */
	size_t start;	/* internal starting offset in buffer of first byte of object - { */
	char backup;	/* internal we store byte we overwrote with \0 when we were ready */
	int ready;	/* internal we indicate to the next call that we were ready previous time */
}; /* note that no memory is transfered. in is copied and return mustn't be freed. */
char * dc_json (struct dc_json * j, const char * in, int ln) { /* detects start/end in JSON stream */
	size_t i;	/* input a null terminated string and ln==-1 - a chunk of the json stream */
	if (!j->buf)	/* of if you know the length or string is not null terminated, set ln. */
		(j->buf = malloc((j->bufcap = 1024) * sizeof(char)))[0] = '\0';
	if (j->ready) {
		if (j->ready > 0)
			memmove(j->buf, j->buf+j->ready, strlen(j->buf+j->ready)+1);
		j->buf[0] = j->backup;
	}
	size_t bufstrlen = strlen(j->buf);	/* could optimize and cache it into the struct */
	if (ln == -1)
		ln = strlen(in);
	i = bufstrlen;
	if (bufstrlen + ln > j->bufcap)
		j->buf = realloc(j->buf, (j->bufcap=(bufstrlen+ln+2)*DC_REALLOC_K)*sizeof(char));
	strncpy(j->buf+bufstrlen, in, ln);
	j->buf[bufstrlen+ln] = '\0';
	bufstrlen += ln;
	while (i < bufstrlen) {
		if (j->instr) {
			if (j->buf[i] == '"') {
				int escaped = 0;
				int index = 0;
				while (j->buf[i-++index] == '\\') {
					if (escaped)
						escaped = 0;
					else
						escaped++;
				}
				if (!escaped) {
					j->instr = 0;
					/* fprintf(stderr, "dc_json: j->instr = 0\n"); */
				} /* else
					fprintf(stderr, "dc_json: escaped\n"); */
			}
			goto next;
		}
		switch (j->buf[i]) {
			case '{':
			case '[':
				if (!j->nest++)
					j->start = i;
				break;
			case '"':
				j->instr++;
				/* fprintf(stderr, "dc_json: j->instr++\n"); */
				break;
			case '}':
			case ']':
				if (!--j->nest) {
					j->backup = j->buf[++i];
					j->ready = i;
					if (!j->backup)
						j->ready = -1;
					j->buf[i] = '\0';
					return j->buf+j->start;
				}
				break;
			default:
				break;
		}
next:
		i++;
	}
	return NULL;
} /* returns pointer to null terminated string when there's an object to be parsed or NULL. */
struct dc_json * dc_json_init () {
	return calloc(1, sizeof(struct dc_json));
}
void dc_json_free (struct dc_json * s) {
	free(s->buf);
	free(s);
}