so://phie

HomeGitCV

libjson

A simple JSON parser

git clone git@soophie.de:/srv/git/libjson

diff --git a/libjson.c b/libjson.c

deleted file mode 100644

index 66a09ac..0000000

--- a/libjson.c

+++ /dev/null

1@@ -1,203 +0,0 @@

2-#include <stdio.h>

3-#include <stdlib.h>

4-#include <stdbool.h>

5-#include <string.h>

6-#include <ctype.h>

7-#include <inttypes.h>

8-

9-#include "libjson.h"

10-

11-char *json_str(json_ptr_t json_ptr) {

12- jsmntok_t token = json_ptr.tokens[json_ptr.ptr];

13- int token_len = token.end - token.start;

14- char *str = malloc(token_len + 1);

15- memcpy(str, json_ptr.str + token.start, token_len);

16- str[token_len] = '\0';

17- return str;

18-}

19-

20-json_ptr_t json_ptr(jsmntok_t *tokens, int len, const char *str) {

21- return (json_ptr_t) {

22- .tokens = tokens,

23- .len = len,

24- .ptr = 0,

25- .str = str,

26- .err = JSON_OK,

27- };

28-}

29-

30-json_ptr_t json_err(json_ptr_t json_ptr, json_err_t json_err) {

31- json_ptr.err = json_err;

32- return json_ptr;

33-}

34-

35-int json_size(json_ptr_t json_ptr) {

36- return json_ptr.tokens[json_ptr.ptr].size;

37-}

38-

39-json_ptr_t json_parse(jsmntok_t tokens[], int tokens_len, const char *str) {

40- jsmn_parser parser;

41- jsmn_init(&parser);

42- int len = jsmn_parse(&parser, str, strlen(str), tokens, tokens_len);

43- json_ptr_t ptr = json_ptr(tokens, len, str);

44- if (len < 0) {

45- return json_err(ptr, JSON_ERR_INVALID_FORMAT);

46- }

47- return ptr;

48-}

49-

50-/**

51- Increments the `jsmntok_t` pointer until the child `JSMN_OBJECT` or

52- `JSMN_ARRAY` is traversed and the pointer points to the next entry.

53- If no errors occured, the return code is `0`.

54-*/

55-void json_seek(json_ptr_t *json_ptr) {

56- jsmntok_t token_root = json_ptr->tokens[json_ptr->ptr];

57- if (token_root.type != JSMN_OBJECT && token_root.type != JSMN_ARRAY) {

58- json_err(*json_ptr, JSON_ERR_INVALID_TYPE);

59- return;

60- }

61- jsmntok_t token;

62- for (int i = 0; i < token_root.size; i++) {

63- if (token_root.type == JSMN_OBJECT) {

64- token = json_ptr->tokens[++json_ptr->ptr]; // key

65- }

66- token = json_ptr->tokens[++json_ptr->ptr]; // value

67- if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {

68- json_seek(json_ptr);

69- if (json_ptr->err) {

70- return;

71- }

72- }

73- }

74-}

75-

76-json_ptr_t json_get(json_ptr_t json_ptr, const char *key) {

77- jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];

78- if (token_root.type != JSMN_OBJECT) {

79- return json_err(json_ptr, JSON_ERR_INVALID_TYPE);

80- }

81- jsmntok_t token;

82- int token_len;

83- while (json_ptr.ptr < json_ptr.len) {

84- token = json_ptr.tokens[++json_ptr.ptr]; // key

85- token_len = token.end - token.start;

86- char token_key[token_len + 1];

87- memcpy(token_key, json_ptr.str + token.start, token_len);

88- token_key[token_len] = '\0';

89- if (strncmp(json_ptr.str + token.start, key, token_len) == 0) {

90- json_ptr.ptr++;

91- return json_ptr;

92- }

93- token = json_ptr.tokens[++json_ptr.ptr]; // value

94- if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {

95- json_seek(&json_ptr);

96- if (json_ptr.err) {

97- return json_ptr;

98- }

99- }

100- }

101- return json_err(json_ptr, JSON_ERR_INVALID_MISSING);

102-}

103-

104-json_ptr_t json_at(json_ptr_t json_ptr, int idx) {

105- jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];

106- if (token_root.type != JSMN_ARRAY) {

107- return json_err(json_ptr, JSON_ERR_INVALID_TYPE);

108- }

109- if (idx >= token_root.size) {

110- return json_err(json_ptr, JSON_ERR_INVALID_SIZE);

111- }

112- jsmntok_t token;

113- int token_idx = 0;

114- while (json_ptr.ptr < json_ptr.len) {

115- token = json_ptr.tokens[++json_ptr.ptr];

116- if (token_idx == idx) {

117- return json_ptr;

118- }

119- if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {

120- json_seek(&json_ptr);

121- if (json_ptr.err) {

122- return json_ptr;

123- }

124- }

125- token_idx++;

126- }

127- return json_err(json_ptr, JSON_ERR_INVALID_MISSING);

128-}

129-

130-json_ptr_t json_query(json_ptr_t json_ptr, const char *query) {

131- jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];

132- if (token_root.type != JSMN_OBJECT && token_root.type != JSMN_ARRAY) {

133- return json_err(json_ptr, JSON_ERR_INVALID_TYPE);

134- }

135- jsmntok_t token;

136- int i = 0;

137- int query_len = strlen(query);

138- while (i < query_len) {

139- token = json_ptr.tokens[json_ptr.ptr];

140- char c = query[i];

141- if (c == '.') {

142- if (token.type != JSMN_OBJECT) {

143- return json_err(json_ptr, JSON_ERR_INVALID_TYPE); // expected JSMN_OBJECT

144- }

145- i++;

146- int j = i;

147- bool found = false;

148- for (; j < query_len; j++) {

149- if (!isalpha(query[j])) {

150- int key_len = j - i;

151- if (key_len == 0) {

152- return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);

153- }

154- char key[key_len + 1];

155- memcpy(key, query + i, key_len);

156- key[key_len] = '\0';

157- json_ptr = json_get(json_ptr, key);

158- i += key_len;

159- found = true;

160- break;

161- }

162- }

163- if (!found) {

164- int key_len = j - i;

165- if (key_len == 0) {

166- return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);

167- }

168- char key[key_len + 1];

169- memcpy(key, query + i, key_len);

170- key[key_len] = '\0';

171- json_ptr = json_get(json_ptr, key);

172- i += key_len;

173- }

174- continue;

175- }

176- if (c == '[') {

177- if (token.type != JSMN_ARRAY) {

178- return json_err(json_ptr, JSON_ERR_INVALID_TYPE); // expected JSMN_ARRAY

179- }

180- i++;

181- for (int j = i; j < query_len; j++) {

182- if (query[j] == ']') {

183- int idx_len = j - i;

184- if (idx_len == 0) {

185- return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);

186- }

187- char idx[idx_len + 1];

188- memcpy(idx, query + i, idx_len);

189- idx[idx_len] = '\0';

190- int index = strtoimax(idx, NULL, 10);

191- json_ptr = json_at(json_ptr, index);

192- i += idx_len + 1;

193- break;

194- }

195- }

196- continue;

197- }

198- if (!isalpha(c)) {

199- return json_err(json_ptr, JSON_ERR_INVALID_FORMAT); // invalid char

200- }

201- i++;

202- }

203- return json_ptr;

204-}

diff --git a/libjson.h b/libjson.h

index 027d7a6..1404c01 100644

--- a/libjson.h

+++ b/libjson.h

1@@ -1,5 +1,9 @@

2-#pragma once

3+#ifndef LIB_JSON_H

4+#define LIB_JSON_H

5

6+#ifndef LIB_JSON_IMPL

7+#define JSMN_HEADER

8+#endif /* LIB_JSON_IMPL */

9 #include <jsmn.h>

10

11 typedef enum {

12@@ -24,3 +28,212 @@ json_ptr_t json_parse(jsmntok_t tokens[], int tokens_len, const char *str);

13 json_ptr_t json_get(json_ptr_t json_ptr, const char *key);

14 json_ptr_t json_at(json_ptr_t json_ptr, int idx);

15 json_ptr_t json_query(json_ptr_t json_ptr, const char *query);

16+

17+#ifdef LIB_JSON_IMPL

18+

19+#include <stdio.h>

20+#include <stdlib.h>

21+#include <stdbool.h>

22+#include <string.h>

23+#include <ctype.h>

24+#include <inttypes.h>

25+

26+#include "libjson.h"

27+

28+char *json_str(json_ptr_t json_ptr) {

29+ jsmntok_t token = json_ptr.tokens[json_ptr.ptr];

30+ int token_len = token.end - token.start;

31+ char *str = malloc(token_len + 1);

32+ memcpy(str, json_ptr.str + token.start, token_len);

33+ str[token_len] = '\0';

34+ return str;

35+}

36+

37+json_ptr_t json_ptr(jsmntok_t *tokens, int len, const char *str) {

38+ return (json_ptr_t) {

39+ .tokens = tokens,

40+ .len = len,

41+ .ptr = 0,

42+ .str = str,

43+ .err = JSON_OK,

44+ };

45+}

46+

47+json_ptr_t json_err(json_ptr_t json_ptr, json_err_t json_err) {

48+ json_ptr.err = json_err;

49+ return json_ptr;

50+}

51+

52+int json_size(json_ptr_t json_ptr) {

53+ return json_ptr.tokens[json_ptr.ptr].size;

54+}

55+

56+json_ptr_t json_parse(jsmntok_t tokens[], int tokens_len, const char *str) {

57+ jsmn_parser parser;

58+ jsmn_init(&parser);

59+ int len = jsmn_parse(&parser, str, strlen(str), tokens, tokens_len);

60+ json_ptr_t ptr = json_ptr(tokens, len, str);

61+ if (len < 0) {

62+ return json_err(ptr, JSON_ERR_INVALID_FORMAT);

63+ }

64+ return ptr;

65+}

66+

67+/**

68+ Increments the `jsmntok_t` pointer until the child `JSMN_OBJECT` or

69+ `JSMN_ARRAY` is traversed and the pointer points to the next entry.

70+ If no errors occured, the return code is `0`.

71+*/

72+void json_seek(json_ptr_t *json_ptr) {

73+ jsmntok_t token_root = json_ptr->tokens[json_ptr->ptr];

74+ if (token_root.type != JSMN_OBJECT && token_root.type != JSMN_ARRAY) {

75+ json_err(*json_ptr, JSON_ERR_INVALID_TYPE);

76+ return;

77+ }

78+ jsmntok_t token;

79+ for (int i = 0; i < token_root.size; i++) {

80+ if (token_root.type == JSMN_OBJECT) {

81+ token = json_ptr->tokens[++json_ptr->ptr]; // key

82+ }

83+ token = json_ptr->tokens[++json_ptr->ptr]; // value

84+ if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {

85+ json_seek(json_ptr);

86+ if (json_ptr->err) {

87+ return;

88+ }

89+ }

90+ }

91+}

92+

93+json_ptr_t json_get(json_ptr_t json_ptr, const char *key) {

94+ jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];

95+ if (token_root.type != JSMN_OBJECT) {

96+ return json_err(json_ptr, JSON_ERR_INVALID_TYPE);

97+ }

98+ jsmntok_t token;

99+ int token_len;

100+ while (json_ptr.ptr < json_ptr.len) {

101+ token = json_ptr.tokens[++json_ptr.ptr]; // key

102+ token_len = token.end - token.start;

103+ char token_key[token_len + 1];

104+ memcpy(token_key, json_ptr.str + token.start, token_len);

105+ token_key[token_len] = '\0';

106+ if (strncmp(json_ptr.str + token.start, key, token_len) == 0) {

107+ json_ptr.ptr++;

108+ return json_ptr;

109+ }

110+ token = json_ptr.tokens[++json_ptr.ptr]; // value

111+ if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {

112+ json_seek(&json_ptr);

113+ if (json_ptr.err) {

114+ return json_ptr;

115+ }

116+ }

117+ }

118+ return json_err(json_ptr, JSON_ERR_INVALID_MISSING);

119+}

120+

121+json_ptr_t json_at(json_ptr_t json_ptr, int idx) {

122+ jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];

123+ if (token_root.type != JSMN_ARRAY) {

124+ return json_err(json_ptr, JSON_ERR_INVALID_TYPE);

125+ }

126+ if (idx >= token_root.size) {

127+ return json_err(json_ptr, JSON_ERR_INVALID_SIZE);

128+ }

129+ jsmntok_t token;

130+ int token_idx = 0;

131+ while (json_ptr.ptr < json_ptr.len) {

132+ token = json_ptr.tokens[++json_ptr.ptr];

133+ if (token_idx == idx) {

134+ return json_ptr;

135+ }

136+ if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {

137+ json_seek(&json_ptr);

138+ if (json_ptr.err) {

139+ return json_ptr;

140+ }

141+ }

142+ token_idx++;

143+ }

144+ return json_err(json_ptr, JSON_ERR_INVALID_MISSING);

145+}

146+

147+json_ptr_t json_query(json_ptr_t json_ptr, const char *query) {

148+ jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];

149+ if (token_root.type != JSMN_OBJECT && token_root.type != JSMN_ARRAY) {

150+ return json_err(json_ptr, JSON_ERR_INVALID_TYPE);

151+ }

152+ jsmntok_t token;

153+ int i = 0;

154+ int query_len = strlen(query);

155+ while (i < query_len) {

156+ token = json_ptr.tokens[json_ptr.ptr];

157+ char c = query[i];

158+ if (c == '.') {

159+ if (token.type != JSMN_OBJECT) {

160+ return json_err(json_ptr, JSON_ERR_INVALID_TYPE); // expected JSMN_OBJECT

161+ }

162+ i++;

163+ int j = i;

164+ bool found = false;

165+ for (; j < query_len; j++) {

166+ if (!isalpha(query[j])) {

167+ int key_len = j - i;

168+ if (key_len == 0) {

169+ return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);

170+ }

171+ char key[key_len + 1];

172+ memcpy(key, query + i, key_len);

173+ key[key_len] = '\0';

174+ json_ptr = json_get(json_ptr, key);

175+ i += key_len;

176+ found = true;

177+ break;

178+ }

179+ }

180+ if (!found) {

181+ int key_len = j - i;

182+ if (key_len == 0) {

183+ return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);

184+ }

185+ char key[key_len + 1];

186+ memcpy(key, query + i, key_len);

187+ key[key_len] = '\0';

188+ json_ptr = json_get(json_ptr, key);

189+ i += key_len;

190+ }

191+ continue;

192+ }

193+ if (c == '[') {

194+ if (token.type != JSMN_ARRAY) {

195+ return json_err(json_ptr, JSON_ERR_INVALID_TYPE); // expected JSMN_ARRAY

196+ }

197+ i++;

198+ for (int j = i; j < query_len; j++) {

199+ if (query[j] == ']') {

200+ int idx_len = j - i;

201+ if (idx_len == 0) {

202+ return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);

203+ }

204+ char idx[idx_len + 1];

205+ memcpy(idx, query + i, idx_len);

206+ idx[idx_len] = '\0';

207+ int index = strtoimax(idx, NULL, 10);

208+ json_ptr = json_at(json_ptr, index);

209+ i += idx_len + 1;

210+ break;

211+ }

212+ }

213+ continue;

214+ }

215+ if (!isalpha(c)) {

216+ return json_err(json_ptr, JSON_ERR_INVALID_FORMAT); // invalid char

217+ }

218+ i++;

219+ }

220+ return json_ptr;

221+}

222+

223+#endif /* LIB_JSON_IMPL */

224+#endif /* LIB_JSON_H */