so://phie

HomeGitCV

libjson

A simple JSON parser

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

diff --git a/Makefile b/Makefile

new file mode 100644

index 0000000..38e8f95

--- /dev/null

+++ b/Makefile

1@@ -0,0 +1,18 @@

2+default: build

3+

4+build:

5+ cc -o libjson.so -shared -fPIC -lpthread -lssl -Wall -Wextra libjson.c

6+

7+install:

8+ cc -o libjson.so -shared -fPIC libjson.c

9+ sudo cp libjson.h /usr/local/include/

10+ sudo cp libjson.so /usr/local/lib/

11+ sudo ldconfig

12+ rm libjson.so

13+

14+uninstall:

15+ sudo rm /usr/local/include/libjson.h

16+ sudo rm /usr/local/lib/libjson.so

17+

18+clean:

19+ rm libjson.so

diff --git a/README.md b/README.md

new file mode 100644

index 0000000..5f7ce93

--- /dev/null

+++ b/README.md

1@@ -0,0 +1,9 @@

2+# libjson

3+

4+A simple JSON parser

5+

6+## Installation

7+

8+```

9+sudo make install

10+```

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

new file mode 100644

index 0000000..66a09ac

--- /dev/null

+++ b/libjson.c

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

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

new file mode 100644

index 0000000..027d7a6

--- /dev/null

+++ b/libjson.h

1@@ -0,0 +1,26 @@

2+#pragma once

3+

4+#include <jsmn.h>

5+

6+typedef enum {

7+ JSON_OK = 0,

8+ JSON_ERR_INVALID_TYPE = 1,

9+ JSON_ERR_INVALID_SIZE = 2,

10+ JSON_ERR_INVALID_FORMAT = 3,

11+ JSON_ERR_INVALID_MISSING = 4,

12+} json_err_t;

13+

14+typedef struct {

15+ jsmntok_t *tokens;

16+ int len;

17+ int ptr;

18+ const char *str;

19+ json_err_t err;

20+} json_ptr_t;

21+

22+char *json_str(json_ptr_t json_ptr);

23+int json_size(json_ptr_t json_ptr);

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

25+json_ptr_t json_get(json_ptr_t json_ptr, const char *key);

26+json_ptr_t json_at(json_ptr_t json_ptr, int idx);

27+json_ptr_t json_query(json_ptr_t json_ptr, const char *query);