Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 1 | /* |
Michael Clark | 837240f | 2007-03-13 08:26:25 +0000 | [diff] [blame] | 2 | * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $ |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 3 | * |
Michael Clark | f6a6e48 | 2007-03-13 08:26:23 +0000 | [diff] [blame] | 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 5 | * Michael Clark <michael@metaparadigm.com> |
| 6 | * |
Michael Clark | f6a6e48 | 2007-03-13 08:26:23 +0000 | [diff] [blame] | 7 | * This library is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the MIT license. See COPYING for details. |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 9 | * |
| 10 | */ |
| 11 | |
| 12 | #include "config.h" |
ehaszla | 252669c | 2010-12-07 18:15:35 +0000 | [diff] [blame] | 13 | #undef realloc |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 14 | |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 15 | #include <stdio.h> |
| 16 | #include <stdlib.h> |
Michael Clark | c8f4a6e | 2007-12-07 02:44:24 +0000 | [diff] [blame] | 17 | #include <stddef.h> |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 18 | #include <limits.h> |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 19 | #include <string.h> |
| 20 | #include <errno.h> |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 21 | #include <ctype.h> |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 22 | |
| 23 | #if HAVE_SYS_TYPES_H |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 24 | #include <sys/types.h> |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 25 | #endif /* HAVE_SYS_TYPES_H */ |
| 26 | |
| 27 | #if HAVE_SYS_STAT_H |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 28 | #include <sys/stat.h> |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 29 | #endif /* HAVE_SYS_STAT_H */ |
| 30 | |
| 31 | #if HAVE_FCNTL_H |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 32 | #include <fcntl.h> |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 33 | #endif /* HAVE_FCNTL_H */ |
| 34 | |
| 35 | #if HAVE_UNISTD_H |
| 36 | # include <unistd.h> |
| 37 | #endif /* HAVE_UNISTD_H */ |
| 38 | |
| 39 | #ifdef WIN32 |
| 40 | # define WIN32_LEAN_AND_MEAN |
| 41 | # include <windows.h> |
| 42 | # include <io.h> |
| 43 | #endif /* defined(WIN32) */ |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 44 | |
Michael Clark | 837240f | 2007-03-13 08:26:25 +0000 | [diff] [blame] | 45 | #if !HAVE_OPEN && defined(WIN32) |
| 46 | # define open _open |
| 47 | #endif |
| 48 | |
| 49 | |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 50 | #include "bits.h" |
| 51 | #include "debug.h" |
| 52 | #include "printbuf.h" |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 53 | #include "json_inttypes.h" |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 54 | #include "json_object.h" |
| 55 | #include "json_tokener.h" |
| 56 | #include "json_util.h" |
| 57 | |
Michael Clark | 88ded9c | 2009-08-27 06:40:59 +0000 | [diff] [blame] | 58 | struct json_object* json_object_from_file(const char *filename) |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 59 | { |
| 60 | struct printbuf *pb; |
| 61 | struct json_object *obj; |
| 62 | char buf[JSON_FILE_BUF_SIZE]; |
| 63 | int fd, ret; |
| 64 | |
| 65 | if((fd = open(filename, O_RDONLY)) < 0) { |
Michael Clark | dfaf670 | 2007-10-25 02:26:00 +0000 | [diff] [blame] | 66 | MC_ERROR("json_object_from_file: error reading file %s: %s\n", |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 67 | filename, strerror(errno)); |
Michael Clark | aaec1ef | 2009-02-25 02:31:32 +0000 | [diff] [blame] | 68 | return (struct json_object*)error_ptr(-1); |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 69 | } |
| 70 | if(!(pb = printbuf_new())) { |
Michael Clark | bd0a567 | 2010-10-13 14:09:41 +0000 | [diff] [blame] | 71 | close(fd); |
Michael Clark | dfaf670 | 2007-10-25 02:26:00 +0000 | [diff] [blame] | 72 | MC_ERROR("json_object_from_file: printbuf_new failed\n"); |
Michael Clark | aaec1ef | 2009-02-25 02:31:32 +0000 | [diff] [blame] | 73 | return (struct json_object*)error_ptr(-1); |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 74 | } |
| 75 | while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { |
| 76 | printbuf_memappend(pb, buf, ret); |
| 77 | } |
| 78 | close(fd); |
| 79 | if(ret < 0) { |
Michael Clark | dfaf670 | 2007-10-25 02:26:00 +0000 | [diff] [blame] | 80 | MC_ABORT("json_object_from_file: error reading file %s: %s\n", |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 81 | filename, strerror(errno)); |
| 82 | printbuf_free(pb); |
Michael Clark | aaec1ef | 2009-02-25 02:31:32 +0000 | [diff] [blame] | 83 | return (struct json_object*)error_ptr(-1); |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 84 | } |
| 85 | obj = json_tokener_parse(pb->buf); |
| 86 | printbuf_free(pb); |
| 87 | return obj; |
| 88 | } |
| 89 | |
| 90 | int json_object_to_file(char *filename, struct json_object *obj) |
| 91 | { |
Michael Clark | 68cafad | 2009-01-06 22:56:57 +0000 | [diff] [blame] | 92 | const char *json_str; |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 93 | int fd, ret; |
| 94 | unsigned int wpos, wsize; |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 95 | |
| 96 | if(!obj) { |
Michael Clark | dfaf670 | 2007-10-25 02:26:00 +0000 | [diff] [blame] | 97 | MC_ERROR("json_object_to_file: object is null\n"); |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 98 | return -1; |
| 99 | } |
| 100 | |
| 101 | if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { |
Michael Clark | dfaf670 | 2007-10-25 02:26:00 +0000 | [diff] [blame] | 102 | MC_ERROR("json_object_to_file: error opening file %s: %s\n", |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 103 | filename, strerror(errno)); |
| 104 | return -1; |
| 105 | } |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 106 | |
Michael Clark | f1ae67d | 2010-10-13 14:10:51 +0000 | [diff] [blame] | 107 | if(!(json_str = json_object_to_json_string(obj))) { |
| 108 | close(fd); |
| 109 | return -1; |
| 110 | } |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 111 | |
| 112 | wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 113 | wpos = 0; |
| 114 | while(wpos < wsize) { |
| 115 | if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { |
| 116 | close(fd); |
Michael Clark | dfaf670 | 2007-10-25 02:26:00 +0000 | [diff] [blame] | 117 | MC_ERROR("json_object_to_file: error writing file %s: %s\n", |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 118 | filename, strerror(errno)); |
| 119 | return -1; |
| 120 | } |
Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 121 | |
| 122 | /* because of the above check for ret < 0, we can safely cast and add */ |
| 123 | wpos += (unsigned int)ret; |
Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 124 | } |
| 125 | |
| 126 | close(fd); |
| 127 | return 0; |
| 128 | } |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 129 | |
| 130 | int json_parse_int64(const char *buf, int64_t *retval) |
| 131 | { |
| 132 | int64_t num64; |
John Arbash Meinel | 6a231e4 | 2012-02-01 09:27:49 +0100 | [diff] [blame] | 133 | const char *buf_skip_space; |
| 134 | int orig_has_neg; |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 135 | if (sscanf(buf, "%" SCNd64, &num64) != 1) |
| 136 | { |
ehaszla | 252669c | 2010-12-07 18:15:35 +0000 | [diff] [blame] | 137 | MC_DEBUG("Failed to parse, sscanf != 1\n"); |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 138 | return 1; |
| 139 | } |
John Arbash Meinel | 6a231e4 | 2012-02-01 09:27:49 +0100 | [diff] [blame] | 140 | buf_skip_space = buf; |
| 141 | orig_has_neg = 0; |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 142 | // Skip leading spaces |
| 143 | while (isspace((int)*buf_skip_space) && *buf_skip_space) |
| 144 | buf_skip_space++; |
| 145 | if (*buf_skip_space == '-') |
| 146 | { |
| 147 | buf_skip_space++; |
| 148 | orig_has_neg = 1; |
| 149 | } |
ehaszla | 252669c | 2010-12-07 18:15:35 +0000 | [diff] [blame] | 150 | // Skip leading zeros, but keep at least one digit |
| 151 | while (buf_skip_space[0] == '0' && buf_skip_space[1] != '\0') |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 152 | buf_skip_space++; |
ehaszla | 252669c | 2010-12-07 18:15:35 +0000 | [diff] [blame] | 153 | if (buf_skip_space[0] == '0' && buf_skip_space[1] == '\0') |
| 154 | orig_has_neg = 0; // "-0" is the same as just plain "0" |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 155 | |
| 156 | if (errno != ERANGE) |
| 157 | { |
| 158 | char buf_cmp[100]; |
| 159 | char *buf_cmp_start = buf_cmp; |
| 160 | int recheck_has_neg = 0; |
John Arbash Meinel | 6a231e4 | 2012-02-01 09:27:49 +0100 | [diff] [blame] | 161 | int buf_cmp_len; |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 162 | snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); |
| 163 | if (*buf_cmp_start == '-') |
| 164 | { |
| 165 | recheck_has_neg = 1; |
| 166 | buf_cmp_start++; |
| 167 | } |
| 168 | // No need to skip leading spaces or zeros here. |
| 169 | |
John Arbash Meinel | 6a231e4 | 2012-02-01 09:27:49 +0100 | [diff] [blame] | 170 | buf_cmp_len = strlen(buf_cmp_start); |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 171 | /** |
| 172 | * If the sign is different, or |
| 173 | * some of the digits are different, or |
| 174 | * there is another digit present in the original string |
| 175 | * then we NOT successfully parsed the value. |
| 176 | */ |
| 177 | if (orig_has_neg != recheck_has_neg || |
| 178 | strncmp(buf_skip_space, buf_cmp_start, strlen(buf_cmp_start)) != 0 || |
| 179 | (strlen(buf_skip_space) != buf_cmp_len && |
ehaszla | 252669c | 2010-12-07 18:15:35 +0000 | [diff] [blame] | 180 | isdigit((int)buf_skip_space[buf_cmp_len]) |
Michael Clark | c4dceae | 2010-10-06 16:39:20 +0000 | [diff] [blame] | 181 | ) |
| 182 | ) |
| 183 | { |
| 184 | errno = ERANGE; |
| 185 | } |
| 186 | } |
| 187 | if (errno == ERANGE) |
| 188 | { |
| 189 | if (orig_has_neg) |
| 190 | num64 = INT64_MIN; |
| 191 | else |
| 192 | num64 = INT64_MAX; |
| 193 | } |
| 194 | *retval = num64; |
| 195 | return 0; |
| 196 | } |
ehaszla | 252669c | 2010-12-07 18:15:35 +0000 | [diff] [blame] | 197 | |
| 198 | #if HAVE_REALLOC == 0 |
| 199 | void* rpl_realloc(void* p, size_t n) |
| 200 | { |
| 201 | if (n == 0) |
| 202 | n = 1; |
| 203 | if (p == 0) |
| 204 | return malloc(n); |
| 205 | return realloc(p, n); |
| 206 | } |
| 207 | #endif |
Eric Haszlakiewicz | 886c4fb | 2011-05-03 20:40:49 +0000 | [diff] [blame] | 208 | |
| 209 | #define NELEM(a) (sizeof(a) / sizeof(a[0])) |
| 210 | static const char* json_type_name[] = { |
| 211 | /* If you change this, be sure to update the enum json_type definition too */ |
| 212 | "null", |
| 213 | "boolean", |
| 214 | "double", |
| 215 | "int", |
| 216 | "object", |
| 217 | "array", |
| 218 | "string", |
| 219 | }; |
| 220 | |
| 221 | const char *json_type_to_name(enum json_type o_type) |
| 222 | { |
| 223 | if (o_type < 0 || o_type >= NELEM(json_type_name)) |
| 224 | { |
| 225 | MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name)); |
| 226 | return NULL; |
| 227 | } |
| 228 | return json_type_name[o_type]; |
| 229 | } |
| 230 | |