1 /* Parse JSON files using the JSMN parser. */ 2 3 /* 4 * Copyright (c) 2014, Intel Corporation 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 28 * OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 */ 31 32 #include <stdlib.h> 33 #include <string.h> 34 #include <sys/mman.h> 35 #include <sys/stat.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <errno.h> 39 #include <unistd.h> 40 #include "jsmn.h" 41 #include "json.h" 42 43 44 static char *mapfile(const char *fn, size_t *size) 45 { 46 unsigned ps = sysconf(_SC_PAGESIZE); 47 struct stat st; 48 char *map = NULL; 49 int err; 50 int fd = open(fn, O_RDONLY); 51 52 if (fd < 0 && verbose > 0 && fn) { 53 pr_err("Error opening events file '%s': %s\n", fn, 54 strerror(errno)); 55 } 56 57 if (fd < 0) 58 return NULL; 59 err = fstat(fd, &st); 60 if (err < 0) 61 goto out; 62 *size = st.st_size; 63 map = mmap(NULL, 64 (st.st_size + ps - 1) & ~(ps - 1), 65 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 66 if (map == MAP_FAILED) 67 map = NULL; 68 out: 69 close(fd); 70 return map; 71 } 72 73 static void unmapfile(char *map, size_t size) 74 { 75 unsigned ps = sysconf(_SC_PAGESIZE); 76 munmap(map, roundup(size, ps)); 77 } 78 79 /* 80 * Parse json file using jsmn. Return array of tokens, 81 * and mapped file. Caller needs to free array. 82 */ 83 jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len) 84 { 85 jsmn_parser parser; 86 jsmntok_t *tokens; 87 jsmnerr_t res; 88 unsigned sz; 89 90 *map = mapfile(fn, size); 91 if (!*map) 92 return NULL; 93 /* Heuristic */ 94 sz = *size * 16; 95 tokens = malloc(sz); 96 if (!tokens) 97 goto error; 98 jsmn_init(&parser); 99 res = jsmn_parse(&parser, *map, *size, tokens, 100 sz / sizeof(jsmntok_t)); 101 if (res != JSMN_SUCCESS) { 102 pr_err("%s: json error %s\n", fn, jsmn_strerror(res)); 103 goto error_free; 104 } 105 if (len) 106 *len = parser.toknext; 107 return tokens; 108 error_free: 109 free(tokens); 110 error: 111 unmapfile(*map, *size); 112 return NULL; 113 } 114 115 void free_json(char *map, size_t size, jsmntok_t *tokens) 116 { 117 free(tokens); 118 unmapfile(map, size); 119 } 120 121 static int countchar(char *map, char c, int end) 122 { 123 int i; 124 int count = 0; 125 for (i = 0; i < end; i++) 126 if (map[i] == c) 127 count++; 128 return count; 129 } 130 131 /* Return line number of a jsmn token */ 132 int json_line(char *map, jsmntok_t *t) 133 { 134 return countchar(map, '\n', t->start) + 1; 135 } 136 137 static const char * const jsmn_types[] = { 138 [JSMN_PRIMITIVE] = "primitive", 139 [JSMN_ARRAY] = "array", 140 [JSMN_OBJECT] = "object", 141 [JSMN_STRING] = "string" 142 }; 143 144 #define LOOKUP(a, i) ((i) < (sizeof(a)/sizeof(*(a))) ? ((a)[i]) : "?") 145 146 /* Return type name of a jsmn token */ 147 const char *json_name(jsmntok_t *t) 148 { 149 return LOOKUP(jsmn_types, t->type); 150 } 151 152 int json_len(jsmntok_t *t) 153 { 154 return t->end - t->start; 155 } 156 157 /* Is string t equal to s? */ 158 int json_streq(char *map, jsmntok_t *t, const char *s) 159 { 160 unsigned len = json_len(t); 161 return len == strlen(s) && !strncasecmp(map + t->start, s, len); 162 } 163