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 * $FreeBSD$ 31 * 32 */ 33 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/mman.h> 37 #include <sys/stat.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <errno.h> 41 #include <unistd.h> 42 #include "jsmn.h" 43 #include "json.h" 44 45 46 static char *mapfile(const char *fn, size_t *size) 47 { 48 unsigned ps = sysconf(_SC_PAGESIZE); 49 struct stat st; 50 char *map = NULL; 51 int err; 52 int fd = open(fn, O_RDONLY); 53 54 if (fd < 0 && verbose > 0 && fn) { 55 pr_err("Error opening events file '%s': %s\n", fn, 56 strerror(errno)); 57 } 58 59 if (fd < 0) 60 return NULL; 61 err = fstat(fd, &st); 62 if (err < 0) 63 goto out; 64 *size = st.st_size; 65 map = mmap(NULL, 66 (st.st_size + ps - 1) & ~(ps - 1), 67 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 68 if (map == MAP_FAILED) 69 map = NULL; 70 out: 71 close(fd); 72 return map; 73 } 74 75 static void unmapfile(char *map, size_t size) 76 { 77 unsigned ps = sysconf(_SC_PAGESIZE); 78 munmap(map, roundup(size, ps)); 79 } 80 81 /* 82 * Parse json file using jsmn. Return array of tokens, 83 * and mapped file. Caller needs to free array. 84 */ 85 jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len) 86 { 87 jsmn_parser parser; 88 jsmntok_t *tokens; 89 jsmnerr_t res; 90 unsigned sz; 91 92 *map = mapfile(fn, size); 93 if (!*map) 94 return NULL; 95 /* Heuristic */ 96 sz = *size * 16; 97 tokens = malloc(sz); 98 if (!tokens) 99 goto error; 100 jsmn_init(&parser); 101 res = jsmn_parse(&parser, *map, *size, tokens, 102 sz / sizeof(jsmntok_t)); 103 if (res != JSMN_SUCCESS) { 104 pr_err("%s: json error %s\n", fn, jsmn_strerror(res)); 105 goto error_free; 106 } 107 if (len) 108 *len = parser.toknext; 109 return tokens; 110 error_free: 111 free(tokens); 112 error: 113 unmapfile(*map, *size); 114 return NULL; 115 } 116 117 void free_json(char *map, size_t size, jsmntok_t *tokens) 118 { 119 free(tokens); 120 unmapfile(map, size); 121 } 122 123 static int countchar(char *map, char c, int end) 124 { 125 int i; 126 int count = 0; 127 for (i = 0; i < end; i++) 128 if (map[i] == c) 129 count++; 130 return count; 131 } 132 133 /* Return line number of a jsmn token */ 134 int json_line(char *map, jsmntok_t *t) 135 { 136 return countchar(map, '\n', t->start) + 1; 137 } 138 139 static const char * const jsmn_types[] = { 140 [JSMN_PRIMITIVE] = "primitive", 141 [JSMN_ARRAY] = "array", 142 [JSMN_OBJECT] = "object", 143 [JSMN_STRING] = "string" 144 }; 145 146 #define LOOKUP(a, i) ((i) < (sizeof(a)/sizeof(*(a))) ? ((a)[i]) : "?") 147 148 /* Return type name of a jsmn token */ 149 const char *json_name(jsmntok_t *t) 150 { 151 return LOOKUP(jsmn_types, t->type); 152 } 153 154 int json_len(jsmntok_t *t) 155 { 156 return t->end - t->start; 157 } 158 159 /* Is string t equal to s? */ 160 int json_streq(char *map, jsmntok_t *t, const char *s) 161 { 162 unsigned len = json_len(t); 163 return len == strlen(s) && !strncasecmp(map + t->start, s, len); 164 } 165