libjson.c (5744B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdbool.h> 4 #include <string.h> 5 #include <ctype.h> 6 #include <inttypes.h> 7 8 #include "libjson.h" 9 10 char *json_str(json_ptr_t json_ptr) { 11 jsmntok_t token = json_ptr.tokens[json_ptr.ptr]; 12 int token_len = token.end - token.start; 13 char *str = malloc(token_len + 1); 14 memcpy(str, json_ptr.str + token.start, token_len); 15 str[token_len] = '\0'; 16 return str; 17 } 18 19 json_ptr_t json_ptr(jsmntok_t *tokens, int len, const char *str) { 20 return (json_ptr_t) { 21 .tokens = tokens, 22 .len = len, 23 .ptr = 0, 24 .str = str, 25 .err = JSON_OK, 26 }; 27 } 28 29 json_ptr_t json_err(json_ptr_t json_ptr, json_err_t json_err) { 30 json_ptr.err = json_err; 31 return json_ptr; 32 } 33 34 int json_size(json_ptr_t json_ptr) { 35 return json_ptr.tokens[json_ptr.ptr].size; 36 } 37 38 json_ptr_t json_parse(jsmntok_t tokens[], int tokens_len, const char *str) { 39 jsmn_parser parser; 40 jsmn_init(&parser); 41 int len = jsmn_parse(&parser, str, strlen(str), tokens, tokens_len); 42 json_ptr_t ptr = json_ptr(tokens, len, str); 43 if (len < 0) { 44 return json_err(ptr, JSON_ERR_INVALID_FORMAT); 45 } 46 return ptr; 47 } 48 49 /** 50 Increments the `jsmntok_t` pointer until the child `JSMN_OBJECT` or 51 `JSMN_ARRAY` is traversed and the pointer points to the next entry. 52 If no errors occured, the return code is `0`. 53 */ 54 void json_seek(json_ptr_t *json_ptr) { 55 jsmntok_t token_root = json_ptr->tokens[json_ptr->ptr]; 56 if (token_root.type != JSMN_OBJECT && token_root.type != JSMN_ARRAY) { 57 json_err(*json_ptr, JSON_ERR_INVALID_TYPE); 58 return; 59 } 60 jsmntok_t token; 61 for (int i = 0; i < token_root.size; i++) { 62 if (token_root.type == JSMN_OBJECT) { 63 token = json_ptr->tokens[++json_ptr->ptr]; // key 64 } 65 token = json_ptr->tokens[++json_ptr->ptr]; // value 66 if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) { 67 json_seek(json_ptr); 68 if (json_ptr->err) { 69 return; 70 } 71 } 72 } 73 } 74 75 json_ptr_t json_get(json_ptr_t json_ptr, const char *key) { 76 jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr]; 77 if (token_root.type != JSMN_OBJECT) { 78 return json_err(json_ptr, JSON_ERR_INVALID_TYPE); 79 } 80 jsmntok_t token; 81 int token_len; 82 while (json_ptr.ptr < json_ptr.len) { 83 token = json_ptr.tokens[++json_ptr.ptr]; // key 84 token_len = token.end - token.start; 85 char token_key[token_len + 1]; 86 memcpy(token_key, json_ptr.str + token.start, token_len); 87 token_key[token_len] = '\0'; 88 if (strncmp(json_ptr.str + token.start, key, token_len) == 0) { 89 json_ptr.ptr++; 90 return json_ptr; 91 } 92 token = json_ptr.tokens[++json_ptr.ptr]; // value 93 if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) { 94 json_seek(&json_ptr); 95 if (json_ptr.err) { 96 return json_ptr; 97 } 98 } 99 } 100 return json_err(json_ptr, JSON_ERR_INVALID_MISSING); 101 } 102 103 json_ptr_t json_at(json_ptr_t json_ptr, int idx) { 104 jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr]; 105 if (token_root.type != JSMN_ARRAY) { 106 return json_err(json_ptr, JSON_ERR_INVALID_TYPE); 107 } 108 if (idx >= token_root.size) { 109 return json_err(json_ptr, JSON_ERR_INVALID_SIZE); 110 } 111 jsmntok_t token; 112 int token_idx = 0; 113 while (json_ptr.ptr < json_ptr.len) { 114 token = json_ptr.tokens[++json_ptr.ptr]; 115 if (token_idx == idx) { 116 return json_ptr; 117 } 118 if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) { 119 json_seek(&json_ptr); 120 if (json_ptr.err) { 121 return json_ptr; 122 } 123 } 124 token_idx++; 125 } 126 return json_err(json_ptr, JSON_ERR_INVALID_MISSING); 127 } 128 129 json_ptr_t json_query(json_ptr_t json_ptr, const char *query) { 130 jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr]; 131 if (token_root.type != JSMN_OBJECT && token_root.type != JSMN_ARRAY) { 132 return json_err(json_ptr, JSON_ERR_INVALID_TYPE); 133 } 134 jsmntok_t token; 135 int i = 0; 136 int query_len = strlen(query); 137 while (i < query_len) { 138 token = json_ptr.tokens[json_ptr.ptr]; 139 char c = query[i]; 140 if (c == '.') { 141 if (token.type != JSMN_OBJECT) { 142 return json_err(json_ptr, JSON_ERR_INVALID_TYPE); // expected JSMN_OBJECT 143 } 144 i++; 145 int j = i; 146 bool found = false; 147 for (; j < query_len; j++) { 148 if (!isalpha(query[j])) { 149 int key_len = j - i; 150 if (key_len == 0) { 151 return json_err(json_ptr, JSON_ERR_INVALID_FORMAT); 152 } 153 char key[key_len + 1]; 154 memcpy(key, query + i, key_len); 155 key[key_len] = '\0'; 156 json_ptr = json_get(json_ptr, key); 157 i += key_len; 158 found = true; 159 break; 160 } 161 } 162 if (!found) { 163 int key_len = j - i; 164 if (key_len == 0) { 165 return json_err(json_ptr, JSON_ERR_INVALID_FORMAT); 166 } 167 char key[key_len + 1]; 168 memcpy(key, query + i, key_len); 169 key[key_len] = '\0'; 170 json_ptr = json_get(json_ptr, key); 171 i += key_len; 172 } 173 continue; 174 } 175 if (c == '[') { 176 if (token.type != JSMN_ARRAY) { 177 return json_err(json_ptr, JSON_ERR_INVALID_TYPE); // expected JSMN_ARRAY 178 } 179 i++; 180 for (int j = i; j < query_len; j++) { 181 if (query[j] == ']') { 182 int idx_len = j - i; 183 if (idx_len == 0) { 184 return json_err(json_ptr, JSON_ERR_INVALID_FORMAT); 185 } 186 char idx[idx_len + 1]; 187 memcpy(idx, query + i, idx_len); 188 idx[idx_len] = '\0'; 189 int index = strtoimax(idx, NULL, 10); 190 json_ptr = json_at(json_ptr, index); 191 i += idx_len + 1; 192 break; 193 } 194 } 195 continue; 196 } 197 if (!isalpha(c)) { 198 return json_err(json_ptr, JSON_ERR_INVALID_FORMAT); // invalid char 199 } 200 i++; 201 } 202 return json_ptr; 203 }